xref: /f-stack/dpdk/devtools/check-includes.sh (revision ec61049c)
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	'exec-env/*' \
84	'rte_vhost.h' \
85	'rte_eth_vhost.h' \
86	'rte_eal_interrupts.h' \
87}
88: ${IGNORE_CXX= \
89	'rte_vhost.h' \
90	'rte_eth_vhost.h' \
91}
92
93temp_cc=$(mktemp -t dpdk.${0##*/}.XXX.c)
94pass_cc=
95failures_cc=0
96
97temp_cxx=$(mktemp -t dpdk.${0##*/}.XXX.cc)
98pass_cxx=
99failures_cxx=0
100
101# Process output parameters.
102
103[ "$QUIET" = 1 ] &&
104exec 1> /dev/null
105
106[ "$VERBOSE" = 1 ] &&
107output ()
108{
109	local CCV
110	local CXXV
111
112	shift
113	CCV=$CC
114	CXXV=$CXX
115	CC="echo $CC" CXX="echo $CXX" "$@"
116	CC=$CCV
117	CXX=$CXXV
118
119	"$@"
120} ||
121output ()
122{
123
124	printf '  %s\n' "$1"
125	shift
126	"$@"
127}
128
129trap 'rm -f "$temp_cc" "$temp_cxx"' EXIT
130
131compile_cc ()
132{
133	${CC} -I"$include_dir" \
134		${PEDANTIC_CPPFLAGS} ${CPPFLAGS} ${EXTRA_CPPFLAGS} \
135		${PEDANTIC_CFLAGS} ${CFLAGS} ${EXTRA_CFLAGS} \
136		-c -o /dev/null "${temp_cc}"
137}
138
139compile_cxx ()
140{
141	${CXX} -I"$include_dir" \
142		${PEDANTIC_CPPFLAGS} ${CPPFLAGS} ${EXTRA_CPPFLAGS} \
143		${PEDANTIC_CXXFLAGS} ${CXXFLAGS} ${EXTRA_CXXFLAGS} \
144		-c -o /dev/null "${temp_cxx}"
145}
146
147ignore ()
148{
149	file="$1"
150	shift
151	while [ $# -ne 0 ]; do
152		case "$file" in
153		$1)
154			return 0
155			;;
156		esac
157		shift
158	done
159	return 1
160}
161
162# Check C/C++ compilation for each header file.
163
164while read -r path
165do
166	file=${path#$include_dir}
167	file=${file##/}
168	if ignore "$file" $IGNORE; then
169		output "SKIP $file" :
170		continue
171	fi
172	if printf "\
173#include <%s>
174
175int main(void)
176{
177	return 0;
178}
179" "$file" > "$temp_cc" &&
180		output "CC $file" compile_cc
181	then
182		pass_cc="$pass_cc $file"
183	else
184		failures_cc=$(($failures_cc + 1))
185	fi
186	if ignore "$file" $IGNORE_CXX; then
187		output "SKIP CXX $file" :
188		continue
189	fi
190	if printf "\
191#include <%s>
192
193int main()
194{
195}
196" "$file" > "$temp_cxx" &&
197		output "CXX $file" compile_cxx
198	then
199		pass_cxx="$pass_cxx $file"
200	else
201		failures_cxx=$(($failures_cxx + 1))
202	fi
203done <<EOF
204$(find "$include_dir" -name '*.h')
205EOF
206
207# Check C compilation with all includes.
208
209: > "$temp_cc" &&
210for file in $pass_cc; do
211	printf "\
212#include <%s>
213" "$file" >> $temp_cc
214done
215if printf "\
216int main(void)
217{
218	return 0;
219}
220" >> "$temp_cc" &&
221	output "CC (all includes that did not fail)" compile_cc
222then
223	:
224else
225	failures_cc=$(($failures_cc + 1))
226fi
227
228# Check C++ compilation with all includes.
229
230: > "$temp_cxx" &&
231for file in $pass_cxx; do
232	printf "\
233#include <%s>
234" "$file" >> $temp_cxx
235done
236if printf "\
237int main()
238{
239}
240" >> "$temp_cxx" &&
241	output "CXX (all includes that did not fail)" compile_cxx
242then
243	:
244else
245	failures_cxx=$(($failures_cxx + 1))
246fi
247
248# Report results.
249
250if [ "$SUMMARY" = 1 ]; then
251	printf "\
252Summary:
253 %u failure(s) for C using '%s'.
254 %u failure(s) for C++ using '%s'.
255" $failures_cc "$CC" $failures_cxx "$CXX" 1>&2
256fi
257
258# Exit with nonzero status if there are failures.
259
260[ $failures_cc -eq 0 ] &&
261[ $failures_cxx -eq 0 ]
262