1#!/bin/sh -e 2# 3# BSD LICENSE 4# 5# Copyright 2016 6WIND S.A. 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions 9# are met: 10# 11# * Redistributions of source code must retain the above copyright 12# notice, this list of conditions and the following disclaimer. 13# * Redistributions in binary form must reproduce the above copyright 14# notice, this list of conditions and the following disclaimer in 15# the documentation and/or other materials provided with the 16# distribution. 17# * Neither the name of 6WIND S.A. nor the names of its 18# contributors may be used to endorse or promote products derived 19# from this software without specific prior written permission. 20# 21# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 33# This script checks that header files in a given directory do not miss 34# dependencies when included on their own, do not conflict and accept being 35# compiled with the strictest possible flags. 36# 37# Files are looked up in the directory provided as the first argument, 38# otherwise build/include by default. 39# 40# Recognized environment variables: 41# 42# VERBOSE=1 is the same as -v. 43# 44# QUIET=1 is the same as -q. 45# 46# SUMMARY=1 is the same as -s. 47# 48# CC, CPPFLAGS, CFLAGS, EXTRA_CPPFLAGS, EXTRA_CFLAGS, CXX, CXXFLAGS and 49# EXTRA_CXXFLAGS are taken into account. 50# 51# PEDANTIC_CFLAGS, PEDANTIC_CXXFLAGS and PEDANTIC_CPPFLAGS provide strict 52# C/C++ compilation flags. 53# 54# IGNORE contains a list of shell patterns matching files (relative to the 55# include directory) to avoid. It is set by default to known DPDK headers 56# which must not be included on their own. 57# 58# IGNORE_CXX provides additional files for C++. 59 60while getopts hqvs arg; do 61 case $arg in 62 h) 63 cat <<EOF 64usage: $0 [-h] [-q] [-v] [-s] [DIR] 65 66This script checks that header files in a given directory do not miss 67dependencies when included on their own, do not conflict and accept being 68compiled with the strictest possible flags. 69 70 -h display this help and exit 71 -q quiet mode, disable normal output 72 -v show command lines being executed 73 -s show summary 74 75With no DIR, default to build/include. 76 77Any failed header check yields a nonzero exit status. 78EOF 79 exit 80 ;; 81 q) 82 QUIET=1 83 ;; 84 v) 85 VERBOSE=1 86 ;; 87 s) 88 SUMMARY=1 89 ;; 90 *) 91 exit 1 92 ;; 93 esac 94done 95 96shift $(($OPTIND - 1)) 97 98include_dir=${1:-build/include} 99 100: ${PEDANTIC_CFLAGS=-std=c99 -pedantic -Wall -Wextra -Werror} 101: ${PEDANTIC_CXXFLAGS=} 102: ${PEDANTIC_CPPFLAGS=-D_XOPEN_SOURCE=600} 103: ${CC:=cc} 104: ${CXX:=c++} 105: ${IGNORE= \ 106 'rte_atomic_32.h' \ 107 'rte_atomic_64.h' \ 108 'rte_byteorder_32.h' \ 109 'rte_byteorder_64.h' \ 110 'generic/*' \ 111 'exec-env/*' \ 112 'rte_vhost.h' \ 113 'rte_eth_vhost.h' \ 114} 115: ${IGNORE_CXX= \ 116 'rte_vhost.h' \ 117 'rte_eth_vhost.h' \ 118} 119 120temp_cc=/tmp/${0##*/}.$$.c 121pass_cc= 122failures_cc=0 123 124temp_cxx=/tmp/${0##*/}.$$.cc 125pass_cxx= 126failures_cxx=0 127 128# Process output parameters. 129 130[ "$QUIET" = 1 ] && 131exec 1> /dev/null 132 133[ "$VERBOSE" = 1 ] && 134output () 135{ 136 local CCV 137 local CXXV 138 139 shift 140 CCV=$CC 141 CXXV=$CXX 142 CC="echo $CC" CXX="echo $CXX" "$@" 143 CC=$CCV 144 CXX=$CXXV 145 146 "$@" 147} || 148output () 149{ 150 151 printf ' %s\n' "$1" 152 shift 153 "$@" 154} 155 156trap 'rm -f "$temp_cc" "$temp_cxx"' EXIT 157 158compile_cc () 159{ 160 ${CC} -I"$include_dir" \ 161 ${PEDANTIC_CPPFLAGS} ${CPPFLAGS} ${EXTRA_CPPFLAGS} \ 162 ${PEDANTIC_CFLAGS} ${CFLAGS} ${EXTRA_CFLAGS} \ 163 -c -o /dev/null "${temp_cc}" 164} 165 166compile_cxx () 167{ 168 ${CXX} -I"$include_dir" \ 169 ${PEDANTIC_CPPFLAGS} ${CPPFLAGS} ${EXTRA_CPPFLAGS} \ 170 ${PEDANTIC_CXXFLAGS} ${CXXFLAGS} ${EXTRA_CXXFLAGS} \ 171 -c -o /dev/null "${temp_cxx}" 172} 173 174ignore () 175{ 176 file="$1" 177 shift 178 while [ $# -ne 0 ]; do 179 case "$file" in 180 $1) 181 return 0 182 ;; 183 esac 184 shift 185 done 186 return 1 187} 188 189# Check C/C++ compilation for each header file. 190 191while read -r path 192do 193 file=${path#$include_dir} 194 file=${file##/} 195 if ignore "$file" $IGNORE; then 196 output "SKIP $file" : 197 continue 198 fi 199 if printf "\ 200#include <%s> 201 202int main(void) 203{ 204 return 0; 205} 206" "$file" > "$temp_cc" && 207 output "CC $file" compile_cc 208 then 209 pass_cc="$pass_cc $file" 210 else 211 failures_cc=$(($failures_cc + 1)) 212 fi 213 if ignore "$file" $IGNORE_CXX; then 214 output "SKIP CXX $file" : 215 continue 216 fi 217 if printf "\ 218#include <%s> 219 220int main() 221{ 222} 223" "$file" > "$temp_cxx" && 224 output "CXX $file" compile_cxx 225 then 226 pass_cxx="$pass_cxx $file" 227 else 228 failures_cxx=$(($failures_cxx + 1)) 229 fi 230done <<EOF 231$(find "$include_dir" -name '*.h') 232EOF 233 234# Check C compilation with all includes. 235 236: > "$temp_cc" && 237for file in $pass_cc; do 238 printf "\ 239#include <%s> 240" "$file" >> $temp_cc 241done 242if printf "\ 243int main(void) 244{ 245 return 0; 246} 247" >> "$temp_cc" && 248 output "CC (all includes that did not fail)" compile_cc 249then 250 : 251else 252 failures_cc=$(($failures_cc + 1)) 253fi 254 255# Check C++ compilation with all includes. 256 257: > "$temp_cxx" && 258for file in $pass_cxx; do 259 printf "\ 260#include <%s> 261" "$file" >> $temp_cxx 262done 263if printf "\ 264int main() 265{ 266} 267" >> "$temp_cxx" && 268 output "CXX (all includes that did not fail)" compile_cxx 269then 270 : 271else 272 failures_cxx=$(($failures_cxx + 1)) 273fi 274 275# Report results. 276 277if [ "$SUMMARY" = 1 ]; then 278 printf "\ 279Summary: 280 %u failure(s) for C using '%s'. 281 %u failure(s) for C++ using '%s'. 282" $failures_cc "$CC" $failures_cxx "$CXX" 1>&2 283fi 284 285# Exit with nonzero status if there are failures. 286 287[ $failures_cc -eq 0 ] && 288[ $failures_cxx -eq 0 ] 289