summaryrefslogtreecommitdiffstats
path: root/src/tools/pginclude/pgrminclude
blob: 7cbd2e7c9cab1d9a4c2ac303550a5ef9afb17376 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
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