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