reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
#!/bin/bash

# diag-build: a tool showing enabled warnings in a project.
#
# diag-build acts as a wrapper for 'diagtool show-enabled', in the same way
# that scan-build acts as a wrapper for the static analyzer. The common case is
# simple: use 'diag-build make' or 'diag-build xcodebuild' to list the warnings
# enabled for the first compilation command we see. Other build systems require
# you to manually specify "dry-run" and "use $CC and $CXX"; if there is a build
# system you are interested in, please add it to the switch statement.

print_usage () {
    echo 'Usage: diag-build.sh [-v] xcodebuild [flags]'
    echo '       diag-build.sh [-v] make [flags]'
    echo '       diag-build.sh [-v] <other build command>'
    echo
    echo 'diagtool must be in your PATH'
    echo 'If using an alternate build command, you must ensure that'
    echo 'the compiler used matches the CC environment variable.'
}

# Mac OS X's BSD sed uses -E for extended regular expressions,
# but GNU sed uses -r. Find out which one this system accepts.
EXTENDED_SED_FLAG='-E'
echo -n | sed $EXTENDED_SED_FLAG 's/a/b/' 2>/dev/null || EXTENDED_SED_FLAG='-r'

if [[ "$1" == "-v" ]]; then
    verbose=$1
    shift
fi

guessing_cc=0

if [[ -z "$CC" ]]; then
    guessing_cc=1
    if [[ -x $(dirname $0)/clang ]]; then
	CC=$(dirname $0)/clang
    elif [[ ! -z $(which clang) ]]; then
	CC=$(which clang)
    else
	echo -n 'Error: could not find an appropriate compiler'
	echo ' to generate build commands.' 1>&2
	echo 'Use the CC environment variable to set one explicitly.' 1>&2
	exit 1
    fi
fi

if [[ -z "$CXX" ]]; then
    if [[ -x $(dirname $0)/clang++ ]]; then
	CXX=$(dirname $0)/clang++
    elif [[ ! -z $(which clang++) ]]; then
	CXX=$(which clang++)
    else
	CXX=$CC
    fi
fi

diagtool=$(which diagtool)
if [[ -z "$diagtool" ]]; then
    if [[ -x $(dirname $0)/diagtool ]]; then
	diagtool=$(dirname $0)/diagtool
    else
	echo 'Error: could not find diagtool.' 1>&2
	exit 1
    fi
fi


tool=$1
shift

if [[ -z "$tool" ]]; then
    print_usage
    exit 1
elif [[ "$tool" == "xcodebuild" ]]; then
    dry_run='-dry-run'
    set_compiler="CC='$CC' CXX='$CXX'"
elif [[ "$tool" == "make" ]]; then
    dry_run='-n'
    set_compiler="CC='$CC' CXX='$CXX'"
else
    echo "Warning: unknown build system '$tool'" 1>&2
    if [[ $guessing_cc -eq 1 ]]; then
	# FIXME: We really only need $CC /or/ $CXX
	echo 'Error: $CC must be set for other build systems' 1>&2
	exit 1
    fi
fi

escape () {
    echo $@ | sed 's:[]:\\|/.+*?^$(){}[]:\\&:g'
}

escCC=$(escape $CC)
escCXX=$(escape $CXX)
command=$(
    eval $tool $dry_run $set_compiler $@ 2>/dev/null |
    # Remove "if" early on so we can find the right command line.
    sed $EXTENDED_SED_FLAG "s:^[[:blank:]]*if[[:blank:]]{1,}::g" |
    # Combine lines with trailing backslashes
    sed -e :a -e '/\\$/N; s/\\\n//; ta' |
    grep -E "^[[:blank:]]*($escCC|$escCXX)" |
    head -n1 |
    sed $EXTENDED_SED_FLAG "s:($escCC|$escCXX):${diagtool//:/\\:} show-enabled:g"
)

if [[ -z "$command" ]]; then
    echo 'Error: could not find any build commands.' 1>&2
    if [[ "$tool" != "xcodebuild" ]]; then
	# xcodebuild always echoes the compile commands on their own line,
	# but other tools give no such guarantees.
	echo -n 'This may occur if your build system embeds the call to ' 2>&1
	echo -n 'the compiler in a larger expression. ' 2>&1
    fi
    exit 2
fi

# Chop off trailing '&&', '||', and ';'
command=${command%%&&*}
command=${command%%||*}
command=${command%%;*}

[[ -n "$verbose" ]] && echo $command
eval $command