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