summaryrefslogtreecommitdiffstats
path: root/src/tools/pginclude
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:17:33 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:17:33 +0000
commit5e45211a64149b3c659b90ff2de6fa982a5a93ed (patch)
tree739caf8c461053357daa9f162bef34516c7bf452 /src/tools/pginclude
parentInitial commit. (diff)
downloadpostgresql-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 '')
-rw-r--r--src/tools/pginclude/README103
-rwxr-xr-xsrc/tools/pginclude/cpluspluscheck175
-rwxr-xr-xsrc/tools/pginclude/headerscheck159
-rwxr-xr-xsrc/tools/pginclude/pgcheckdefines305
-rwxr-xr-xsrc/tools/pginclude/pgcompinclude47
-rwxr-xr-xsrc/tools/pginclude/pgdefine25
-rwxr-xr-xsrc/tools/pginclude/pgfixinclude21
-rwxr-xr-xsrc/tools/pginclude/pgrminclude149
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