]> granicus.if.org Git - libexpat/blob - expat/qa.sh
qa.sh: Auto-detect QA_COMPILER
[libexpat] / expat / qa.sh
1 #! /usr/bin/env bash
2 # Copyright (C) 2016 Sebastian Pipping <sebastian@pipping.org>
3 # Licensed under MIT license
4
5 set -e
6 set -o nounset
7
8
9 ANNOUNCE() {
10     local open='\e[1m'
11     local close='\e[0m'
12
13     echo -e -n "${open}" >&2
14     echo -n "# $*" >&2
15     echo -e "${close}" >&2
16 }
17
18
19 WARNING() {
20     local open='\e[1;33m'
21     local close='\e[0m'
22
23     echo -e -n "${open}" >&2
24     echo -n "WARNING: $*" >&2
25     echo -e "${close}" >&2
26 }
27
28
29 RUN() {
30     ANNOUNCE "$@"
31     env "$@"
32 }
33
34
35 populate_environment() {
36     : ${MAKE:=make}
37
38     case "${QA_COMPILER}" in
39         clang)
40             : ${CC:=clang}
41             : ${CXX:=clang++}
42             : ${LD:=clang++}
43             ;;
44         gcc)
45             : ${CC:=gcc}
46             : ${CXX:=g++}
47             : ${LD:=ld}
48             ;;
49     esac
50
51     : ${BASE_COMPILE_FLAGS:="-pipe -Wall -Wextra -pedantic -Wno-overlength-strings -Wno-long-long"}
52     : ${BASE_LINK_FLAGS:=}
53
54     if [[ ${QA_COMPILER} = clang ]]; then
55         case "${QA_SANITIZER}" in
56             address)
57                 # http://clang.llvm.org/docs/AddressSanitizer.html
58                 BASE_COMPILE_FLAGS+=" -g -fsanitize=address -fno-omit-frame-pointer -fno-common"
59                 BASE_LINK_FLAGS+=" -g -fsanitize=address"
60                 ;;
61             memory)
62                 # http://clang.llvm.org/docs/MemorySanitizer.html
63                 BASE_COMPILE_FLAGS+=" -fsanitize=memory -fno-omit-frame-pointer -g -O2 -fsanitize-memory-track-origins -fsanitize-blacklist=$PWD/memory-sanitizer-blacklist.txt"
64                 ;;
65             undefined)
66                 # http://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
67                 BASE_COMPILE_FLAGS+=" -fsanitize=undefined"
68                 BASE_LINK_FLAGS+=" -fsanitize=undefined"
69                 export UBSAN_OPTIONS="print_stacktrace=1:halt_on_error=1:abort_on_error=1"
70                 ;;
71         esac
72     fi
73
74
75     if [[ ${QA_COMPILER} = gcc ]]; then
76         case "${QA_PROCESSOR}" in
77             egypt) BASE_COMPILE_FLAGS+=" -fdump-rtl-expand" ;;
78             gcov) BASE_COMPILE_FLAGS+=" --coverage -O0" ;;
79         esac
80     fi
81
82
83     CFLAGS="-std=c99 ${BASE_COMPILE_FLAGS} ${CFLAGS:-}"
84     CXXFLAGS="-std=c++98 ${BASE_COMPILE_FLAGS} ${CXXFLAGS:-}"
85     LDFLAGS="${BASE_LINK_FLAGS} ${LDFLAGS:-}"
86 }
87
88
89 run_cmake() {
90     local cmake_args=(
91         -DCMAKE_C_COMPILER="${CC}"
92         -DCMAKE_C_FLAGS="${CFLAGS}"
93
94         -DCMAKE_CXX_COMPILER="${CXX}"
95         -DCMAKE_CXX_FLAGS="${CXXFLAGS}"
96
97         -DCMAKE_LINKER="${LD}"
98         -DCMAKE_EXE_LINKER_FLAGS="${LDFLAGS}"
99         -DCMAKE_SHARED_LINKER_FLAGS="${LDFLAGS}"
100
101         -DEXPAT_WARNINGS_AS_ERRORS=ON
102     )
103     RUN cmake "${cmake_args[@]}" "$@" .
104 }
105
106
107 run_compile() {
108     local make_args=(
109         VERBOSE=1
110         -j2
111     )
112
113     RUN "${MAKE}" "${make_args[@]}" clean all
114 }
115
116
117 run_tests() {
118     case "${QA_PROCESSOR}" in
119         egypt) return 0 ;;
120     esac
121
122     if [[ ${CC} =~ mingw ]]; then
123         # NOTE: Filenames are hardcoded for Travis Ubuntu trusty, as of now
124         for i in tests xmlwf ; do
125             RUN ln -s \
126                     /usr/i686-w64-mingw32/lib/libwinpthread-1.dll \
127                     /usr/lib/gcc/i686-w64-mingw32/*/libgcc_s_sjlj-1.dll \
128                     /usr/lib/gcc/i686-w64-mingw32/*/libstdc++-6.dll \
129                     "$PWD"/libexpat.dll \
130                     ${i}/
131         done
132     fi
133
134     local make_env_args=(
135         CTEST_OUTPUT_ON_FAILURE=1
136         CTEST_PARALLEL_LEVEL=2
137         VERBOSE=1
138     )
139
140     RUN "${MAKE}" "${make_env_args[@]}" test run-xmltest
141 }
142
143
144 run_processor() {
145     if [[ ${QA_COMPILER} != gcc ]]; then
146         return 0
147     fi
148
149     case "${QA_PROCESSOR}" in
150     egypt)
151         local DOT_FORMAT="${DOT_FORMAT:-svg}"
152         local o="callgraph.${DOT_FORMAT}"
153         ANNOUNCE "egypt ...... | dot ...... > ${o}"
154         find -name '*.expand' \
155                 | sort \
156                 | xargs -r egypt \
157                 | unflatten -c 20 \
158                 | dot -T${DOT_FORMAT} -Grankdir=LR \
159                 > "${o}"
160         ;;
161     gcov)
162         for gcov_dir in lib xmlwf ; do
163         (
164             cd "${gcov_dir}" || exit 1
165             for gcda_file in $(find . -name '*.gcda' | sort) ; do
166                 RUN gcov -s .libs/ ${gcda_file}
167             done
168         )
169         done
170
171         RUN find -name '*.gcov' | sort
172         ;;
173     esac
174 }
175
176
177 run() {
178     populate_environment
179     dump_config
180
181     run_cmake "$@"
182     run_compile
183     run_tests
184     run_processor
185 }
186
187
188 dump_config() {
189     cat <<EOF
190 Configuration:
191   QA_COMPILER=${QA_COMPILER}  # auto-detected from \$CC and \$CXX
192   QA_PROCESSOR=${QA_PROCESSOR}  # GCC only
193   QA_SANITIZER=${QA_SANITIZER}  # Clang only
194
195   CFLAGS=${CFLAGS}
196   CXXFLAGS=${CXXFLAGS}
197   LDFLAGS=${LDFLAGS}
198
199   CC=${CC}
200   CXX=${CXX}
201   LD=${LD}
202   MAKE=${MAKE}
203
204 Compiler (\$CC):
205 EOF
206     "${CC}" --version | sed 's,^,  ,'
207     echo
208 }
209
210
211 classify_compiler() {
212     local i
213     for i in "${CC:-}" "${CXX:-}"; do
214         [[ "$i" =~ clang ]] && { echo clang ; return ; }
215     done
216     echo gcc
217 }
218
219
220 process_config() {
221     case "${QA_COMPILER:=$(classify_compiler)}" in
222         clang|gcc) ;;
223         *) usage; exit 1 ;;
224     esac
225
226
227     if [[ ${QA_COMPILER} != gcc && -n ${QA_PROCESSOR:-} ]]; then
228         WARNING "QA_COMPILER=${QA_COMPILER} is not 'gcc' -- ignoring QA_PROCESSOR=${QA_PROCESSOR}"
229     fi
230
231     case "${QA_PROCESSOR:=gcov}" in
232         egypt|gcov) ;;
233         *) usage; exit 1 ;;
234     esac
235
236
237     if [[ ${QA_COMPILER} != clang && -n ${QA_SANITIZER:-} ]]; then
238         WARNING "QA_COMPILER=${QA_COMPILER} is not 'clang' -- ignoring QA_SANITIZER=${QA_SANITIZER}" >&2
239     fi
240
241     case "${QA_SANITIZER:=address}" in
242         address|memory|undefined) ;;
243         *) usage; exit 1 ;;
244     esac
245 }
246
247
248 usage() {
249     cat <<"EOF"
250 Usage:
251   $ ./qa.sh [ARG ..]
252
253 Environment variables
254   QA_COMPILER=(clang|gcc)                  # default: auto-detected
255   QA_PROCESSOR=(egypt|gcov)                # default: gcov
256   QA_SANITIZER=(address|memory|undefined)  # default: address
257
258 EOF
259 }
260
261
262 main() {
263     if [[ ${1:-} = --help ]]; then
264         usage; exit 0
265     fi
266
267     process_config
268
269     run "$@"
270 }
271
272
273 main "$@"