xref: /f-stack/dpdk/devtools/check-includes.sh (revision aa61e4b5)
1#!/bin/sh -e
2# SPDX-License-Identifier: BSD-3-Clause
3# Copyright 2016 6WIND S.A.
4
5# This script checks that header files in a given directory do not miss
6# dependencies when included on their own, do not conflict and accept being
7# compiled with the strictest possible flags.
8#
9# Files are looked up in the directory provided as the first argument,
10# otherwise build/include by default.
11#
12# Recognized environment variables:
13#
14# VERBOSE=1 is the same as -v.
15#
16# QUIET=1 is the same as -q.
17#
18# SUMMARY=1 is the same as -s.
19#
20# CC, CPPFLAGS, CFLAGS, EXTRA_CPPFLAGS, EXTRA_CFLAGS, CXX, CXXFLAGS and
21# EXTRA_CXXFLAGS are taken into account.
22#
23# PEDANTIC_CFLAGS, PEDANTIC_CXXFLAGS and PEDANTIC_CPPFLAGS provide strict
24# C/C++ compilation flags.
25#
26# IGNORE contains a list of shell patterns matching files (relative to the
27# include directory) to avoid. It is set by default to known DPDK headers
28# which must not be included on their own.
29#
30# IGNORE_CXX provides additional files for C++.
31
32while getopts hqvs arg; do
33	case $arg in
34	h)
35		cat <<EOF
36usage: $0 [-h] [-q] [-v] [-s] [DIR]
37
38This script checks that header files in a given directory do not miss
39dependencies when included on their own, do not conflict and accept being
40compiled with the strictest possible flags.
41
42  -h    display this help and exit
43  -q    quiet mode, disable normal output
44  -v    show command lines being executed
45  -s    show summary
46
47With no DIR, default to build/include.
48
49Any failed header check yields a nonzero exit status.
50EOF
51		exit
52		;;
53	q)
54		QUIET=1
55		;;
56	v)
57		VERBOSE=1
58		;;
59	s)
60		SUMMARY=1
61		;;
62	*)
63		exit 1
64		;;
65	esac
66done
67
68shift $(($OPTIND - 1))
69
70include_dir=${1:-build/include}
71
72: ${PEDANTIC_CFLAGS=-std=c99 -pedantic -Wall -Wextra -Werror}
73: ${PEDANTIC_CXXFLAGS=}
74: ${PEDANTIC_CPPFLAGS=-D_XOPEN_SOURCE=600}
75: ${CC:=cc}
76: ${CXX:=c++}
77: ${IGNORE= \
78	'rte_atomic_32.h' \
79	'rte_atomic_64.h' \
80	'rte_byteorder_32.h' \
81	'rte_byteorder_64.h' \
82	'generic/*' \
83	'rte_vhost.h' \
84	'rte_eth_vhost.h' \
85	'rte_eal_interrupts.h' \
86}
87: ${IGNORE_CXX= \
88	'rte_vhost.h' \
89	'rte_eth_vhost.h' \
90}
91
92temp_cc=$(mktemp -t dpdk.${0##*/}.XXX.c)
93pass_cc=
94failures_cc=0
95
96temp_cxx=$(mktemp -t dpdk.${0##*/}.XXX.cc)
97pass_cxx=
98failures_cxx=0
99
100# Process output parameters.
101
102[ "$QUIET" = 1 ] &&
103exec 1> /dev/null
104
105[ "$VERBOSE" = 1 ] &&
106output ()
107{
108	local CCV
109	local CXXV
110
111	shift
112	CCV=$CC
113	CXXV=$CXX
114	CC="echo $CC" CXX="echo $CXX" "$@"
115	CC=$CCV
116	CXX=$CXXV
117
118	"$@"
119} ||
120output ()
121{
122
123	printf '  %s\n' "$1"
124	shift
125	"$@"
126}
127
128trap 'rm -f "$temp_cc" "$temp_cxx"' EXIT
129
130compile_cc ()
131{
132	${CC} -I"$include_dir" \
133		${PEDANTIC_CPPFLAGS} ${CPPFLAGS} ${EXTRA_CPPFLAGS} \
134		${PEDANTIC_CFLAGS} ${CFLAGS} ${EXTRA_CFLAGS} \
135		-c -o /dev/null "${temp_cc}"
136}
137
138compile_cxx ()
139{
140	${CXX} -I"$include_dir" \
141		${PEDANTIC_CPPFLAGS} ${CPPFLAGS} ${EXTRA_CPPFLAGS} \
142		${PEDANTIC_CXXFLAGS} ${CXXFLAGS} ${EXTRA_CXXFLAGS} \
143		-c -o /dev/null "${temp_cxx}"
144}
145
146ignore ()
147{
148	file="$1"
149	shift
150	while [ $# -ne 0 ]; do
151		case "$file" in
152		$1)
153			return 0
154			;;
155		esac
156		shift
157	done
158	return 1
159}
160
161# Check C/C++ compilation for each header file.
162
163while read -r path
164do
165	file=${path#$include_dir}
166	file=${file##/}
167	if ignore "$file" $IGNORE; then
168		output "SKIP $file" :
169		continue
170	fi
171	if printf "\
172#include <%s>
173
174int main(void)
175{
176	return 0;
177}
178" "$file" > "$temp_cc" &&
179		output "CC $file" compile_cc
180	then
181		pass_cc="$pass_cc $file"
182	else
183		failures_cc=$(($failures_cc + 1))
184	fi
185	if ignore "$file" $IGNORE_CXX; then
186		output "SKIP CXX $file" :
187		continue
188	fi
189	if printf "\
190#include <%s>
191
192int main()
193{
194}
195" "$file" > "$temp_cxx" &&
196		output "CXX $file" compile_cxx
197	then
198		pass_cxx="$pass_cxx $file"
199	else
200		failures_cxx=$(($failures_cxx + 1))
201	fi
202done <<EOF
203$(find "$include_dir" -name '*.h')
204EOF
205
206# Check C compilation with all includes.
207
208: > "$temp_cc" &&
209for file in $pass_cc; do
210	printf "\
211#include <%s>
212" "$file" >> $temp_cc
213done
214if printf "\
215int main(void)
216{
217	return 0;
218}
219" >> "$temp_cc" &&
220	output "CC (all includes that did not fail)" compile_cc
221then
222	:
223else
224	failures_cc=$(($failures_cc + 1))
225fi
226
227# Check C++ compilation with all includes.
228
229: > "$temp_cxx" &&
230for file in $pass_cxx; do
231	printf "\
232#include <%s>
233" "$file" >> $temp_cxx
234done
235if printf "\
236int main()
237{
238}
239" >> "$temp_cxx" &&
240	output "CXX (all includes that did not fail)" compile_cxx
241then
242	:
243else
244	failures_cxx=$(($failures_cxx + 1))
245fi
246
247# Report results.
248
249if [ "$SUMMARY" = 1 ]; then
250	printf "\
251Summary:
252 %u failure(s) for C using '%s'.
253 %u failure(s) for C++ using '%s'.
254" $failures_cc "$CC" $failures_cxx "$CXX" 1>&2
255fi
256
257# Exit with nonzero status if there are failures.
258
259[ $failures_cc -eq 0 ] &&
260[ $failures_cxx -eq 0 ]
261