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