1*67e74705SXin Li#!/bin/bash 2*67e74705SXin Li 3*67e74705SXin Li# diag-build: a tool showing enabled warnings in a project. 4*67e74705SXin Li# 5*67e74705SXin Li# diag-build acts as a wrapper for 'diagtool show-enabled', in the same way 6*67e74705SXin Li# that scan-build acts as a wrapper for the static analyzer. The common case is 7*67e74705SXin Li# simple: use 'diag-build make' or 'diag-build xcodebuild' to list the warnings 8*67e74705SXin Li# enabled for the first compilation command we see. Other build systems require 9*67e74705SXin Li# you to manually specify "dry-run" and "use $CC and $CXX"; if there is a build 10*67e74705SXin Li# system you are interested in, please add it to the switch statement. 11*67e74705SXin Li 12*67e74705SXin Liprint_usage () { 13*67e74705SXin Li echo 'Usage: diag-build.sh [-v] xcodebuild [flags]' 14*67e74705SXin Li echo ' diag-build.sh [-v] make [flags]' 15*67e74705SXin Li echo ' diag-build.sh [-v] <other build command>' 16*67e74705SXin Li echo 17*67e74705SXin Li echo 'diagtool must be in your PATH' 18*67e74705SXin Li echo 'If using an alternate build command, you must ensure that' 19*67e74705SXin Li echo 'the compiler used matches the CC environment variable.' 20*67e74705SXin Li} 21*67e74705SXin Li 22*67e74705SXin Li# Mac OS X's BSD sed uses -E for extended regular expressions, 23*67e74705SXin Li# but GNU sed uses -r. Find out which one this system accepts. 24*67e74705SXin LiEXTENDED_SED_FLAG='-E' 25*67e74705SXin Liecho -n | sed $EXTENDED_SED_FLAG 's/a/b/' 2>/dev/null || EXTENDED_SED_FLAG='-r' 26*67e74705SXin Li 27*67e74705SXin Liif [[ "$1" == "-v" ]]; then 28*67e74705SXin Li verbose=$1 29*67e74705SXin Li shift 30*67e74705SXin Lifi 31*67e74705SXin Li 32*67e74705SXin Liguessing_cc=0 33*67e74705SXin Li 34*67e74705SXin Liif [[ -z "$CC" ]]; then 35*67e74705SXin Li guessing_cc=1 36*67e74705SXin Li if [[ -x $(dirname $0)/clang ]]; then 37*67e74705SXin Li CC=$(dirname $0)/clang 38*67e74705SXin Li elif [[ ! -z $(which clang) ]]; then 39*67e74705SXin Li CC=$(which clang) 40*67e74705SXin Li else 41*67e74705SXin Li echo -n 'Error: could not find an appropriate compiler' 42*67e74705SXin Li echo ' to generate build commands.' 1>&2 43*67e74705SXin Li echo 'Use the CC environment variable to set one explicitly.' 1>&2 44*67e74705SXin Li exit 1 45*67e74705SXin Li fi 46*67e74705SXin Lifi 47*67e74705SXin Li 48*67e74705SXin Liif [[ -z "$CXX" ]]; then 49*67e74705SXin Li if [[ -x $(dirname $0)/clang++ ]]; then 50*67e74705SXin Li CXX=$(dirname $0)/clang++ 51*67e74705SXin Li elif [[ ! -z $(which clang++) ]]; then 52*67e74705SXin Li CXX=$(which clang++) 53*67e74705SXin Li else 54*67e74705SXin Li CXX=$CC 55*67e74705SXin Li fi 56*67e74705SXin Lifi 57*67e74705SXin Li 58*67e74705SXin Lidiagtool=$(which diagtool) 59*67e74705SXin Liif [[ -z "$diagtool" ]]; then 60*67e74705SXin Li if [[ -x $(dirname $0)/diagtool ]]; then 61*67e74705SXin Li diagtool=$(dirname $0)/diagtool 62*67e74705SXin Li else 63*67e74705SXin Li echo 'Error: could not find diagtool.' 1>&2 64*67e74705SXin Li exit 1 65*67e74705SXin Li fi 66*67e74705SXin Lifi 67*67e74705SXin Li 68*67e74705SXin Li 69*67e74705SXin Litool=$1 70*67e74705SXin Lishift 71*67e74705SXin Li 72*67e74705SXin Liif [[ -z "$tool" ]]; then 73*67e74705SXin Li print_usage 74*67e74705SXin Li exit 1 75*67e74705SXin Lielif [[ "$tool" == "xcodebuild" ]]; then 76*67e74705SXin Li dry_run='-dry-run' 77*67e74705SXin Li set_compiler="CC='$CC' CXX='$CXX'" 78*67e74705SXin Lielif [[ "$tool" == "make" ]]; then 79*67e74705SXin Li dry_run='-n' 80*67e74705SXin Li set_compiler="CC='$CC' CXX='$CXX'" 81*67e74705SXin Lielse 82*67e74705SXin Li echo "Warning: unknown build system '$tool'" 1>&2 83*67e74705SXin Li if [[ $guessing_cc -eq 1 ]]; then 84*67e74705SXin Li # FIXME: We really only need $CC /or/ $CXX 85*67e74705SXin Li echo 'Error: $CC must be set for other build systems' 1>&2 86*67e74705SXin Li exit 1 87*67e74705SXin Li fi 88*67e74705SXin Lifi 89*67e74705SXin Li 90*67e74705SXin Liescape () { 91*67e74705SXin Li echo $@ | sed 's:[]:\\|/.+*?^$(){}[]:\\&:g' 92*67e74705SXin Li} 93*67e74705SXin Li 94*67e74705SXin LiescCC=$(escape $CC) 95*67e74705SXin LiescCXX=$(escape $CXX) 96*67e74705SXin Licommand=$( 97*67e74705SXin Li eval $tool $dry_run $set_compiler $@ 2>/dev/null | 98*67e74705SXin Li # Remove "if" early on so we can find the right command line. 99*67e74705SXin Li sed $EXTENDED_SED_FLAG "s:^[[:blank:]]*if[[:blank:]]{1,}::g" | 100*67e74705SXin Li # Combine lines with trailing backslashes 101*67e74705SXin Li sed -e :a -e '/\\$/N; s/\\\n//; ta' | 102*67e74705SXin Li grep -E "^[[:blank:]]*($escCC|$escCXX)" | 103*67e74705SXin Li head -n1 | 104*67e74705SXin Li sed $EXTENDED_SED_FLAG "s:($escCC|$escCXX):${diagtool//:/\\:} show-enabled:g" 105*67e74705SXin Li) 106*67e74705SXin Li 107*67e74705SXin Liif [[ -z "$command" ]]; then 108*67e74705SXin Li echo 'Error: could not find any build commands.' 1>&2 109*67e74705SXin Li if [[ "$tool" != "xcodebuild" ]]; then 110*67e74705SXin Li # xcodebuild always echoes the compile commands on their own line, 111*67e74705SXin Li # but other tools give no such guarantees. 112*67e74705SXin Li echo -n 'This may occur if your build system embeds the call to ' 2>&1 113*67e74705SXin Li echo -n 'the compiler in a larger expression. ' 2>&1 114*67e74705SXin Li fi 115*67e74705SXin Li exit 2 116*67e74705SXin Lifi 117*67e74705SXin Li 118*67e74705SXin Li# Chop off trailing '&&', '||', and ';' 119*67e74705SXin Licommand=${command%%&&*} 120*67e74705SXin Licommand=${command%%||*} 121*67e74705SXin Licommand=${command%%;*} 122*67e74705SXin Li 123*67e74705SXin Li[[ -n "$verbose" ]] && echo $command 124*67e74705SXin Lieval $command 125