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