diag-build.sh
3.47 KB
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