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