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