xref: /aosp_15_r20/external/expat/expat/qa.sh (revision 6be67779651aebaf20f11e5663acd1ae59e93f66)
1#! /usr/bin/env bash
2#                          __  __            _
3#                       ___\ \/ /_ __   __ _| |_
4#                      / _ \\  /| '_ \ / _` | __|
5#                     |  __//  \| |_) | (_| | |_
6#                      \___/_/\_\ .__/ \__,_|\__|
7#                               |_| XML parser
8#
9# Copyright (c) 2016-2023 Sebastian Pipping <[email protected]>
10# Copyright (c) 2019      Philippe Antoine <[email protected]>
11# Copyright (c) 2019      Hanno Böck <[email protected]>
12# Copyright (c) 2024      Alexander Bluhm <[email protected]>
13# Licensed under the MIT license:
14#
15# Permission is  hereby granted,  free of charge,  to any  person obtaining
16# a  copy  of  this  software   and  associated  documentation  files  (the
17# "Software"),  to  deal in  the  Software  without restriction,  including
18# without  limitation the  rights  to use,  copy,  modify, merge,  publish,
19# distribute, sublicense, and/or sell copies of the Software, and to permit
20# persons  to whom  the Software  is  furnished to  do so,  subject to  the
21# following conditions:
22#
23# The above copyright  notice and this permission notice  shall be included
24# in all copies or substantial portions of the Software.
25#
26# THE  SOFTWARE  IS  PROVIDED  "AS  IS",  WITHOUT  WARRANTY  OF  ANY  KIND,
27# EXPRESS  OR IMPLIED,  INCLUDING  BUT  NOT LIMITED  TO  THE WARRANTIES  OF
28# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
29# NO EVENT SHALL THE AUTHORS OR  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
30# DAMAGES OR  OTHER LIABILITY, WHETHER  IN AN  ACTION OF CONTRACT,  TORT OR
31# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
32# USE OR OTHER DEALINGS IN THE SOFTWARE.
33
34set -e
35set -o nounset
36
37
38ANNOUNCE() {
39    local open='\e[1m'
40    local close='\e[0m'
41
42    echo -e -n "${open}" >&2
43    echo -n "# $*" >&2
44    echo -e "${close}" >&2
45}
46
47
48WARNING() {
49    local open='\e[1;33m'
50    local close='\e[0m'
51
52    echo -e -n "${open}" >&2
53    echo -n "WARNING: $*" >&2
54    echo -e "${close}" >&2
55}
56
57
58RUN() {
59    ANNOUNCE "$@"
60    env "$@"
61}
62
63
64populate_environment() {
65    : ${MAKE:=make}
66
67    case "${QA_COMPILER}" in
68        clang)
69            : ${CC:=clang}
70            : ${CXX:=clang++}
71            : ${LD:=clang++}
72            ;;
73        gcc)
74            : ${CC:=gcc}
75            : ${CXX:=g++}
76            : ${LD:=ld}
77            ;;
78    esac
79
80    : ${BASE_COMPILE_FLAGS:="-pipe -Wall -Wextra -pedantic -Wno-overlength-strings"}
81    : ${BASE_LINK_FLAGS:=}
82
83    if [[ ${QA_COMPILER} = clang ]]; then
84        case "${QA_SANITIZER}" in
85            address)
86                # http://clang.llvm.org/docs/AddressSanitizer.html
87                BASE_COMPILE_FLAGS+=" -g -fsanitize=address -fno-omit-frame-pointer -fno-common"
88                BASE_LINK_FLAGS+=" -g -fsanitize=address"
89                # macOS's XCode does not support LeakSanitizer and reports error:
90                # AddressSanitizer: detect_leaks is not supported on this platform.
91                if [[ "$(uname -s)" != Darwin* ]]; then
92                    export ASAN_OPTIONS=detect_leaks=1
93                fi
94                ;;
95            cfi)
96                BASE_COMPILE_FLAGS+=' -fsanitize=cfi -flto -fvisibility=hidden -fno-sanitize-trap=all -fsanitize-cfi-cross-dso'
97                BASE_LINK_FLAGS+=' -fuse-ld=gold'
98                ;;
99            memory)
100                # http://clang.llvm.org/docs/MemorySanitizer.html
101                BASE_COMPILE_FLAGS+=" -fsanitize=memory -fno-omit-frame-pointer -g -O2 -fsanitize-memory-track-origins -fsanitize-blacklist=$PWD/memory-sanitizer-blacklist.txt"
102                ;;
103            undefined)
104                # http://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
105                BASE_COMPILE_FLAGS+=" -fsanitize=undefined"
106                BASE_LINK_FLAGS+=" -fsanitize=undefined"
107                export UBSAN_OPTIONS="print_stacktrace=1:halt_on_error=1:abort_on_error=1"
108                ;;
109        esac
110    fi
111
112
113    if [[ ${QA_COMPILER} = gcc ]]; then
114        case "${QA_PROCESSOR}" in
115            egypt) BASE_COMPILE_FLAGS+=" -fdump-rtl-expand" ;;
116            gcov) BASE_COMPILE_FLAGS+=" --coverage -O0" ;;
117        esac
118    fi
119
120
121    CFLAGS="-std=c99 ${BASE_COMPILE_FLAGS} ${CFLAGS:-}"
122    CXXFLAGS="-std=c++11 ${BASE_COMPILE_FLAGS} ${CXXFLAGS:-}"
123    LDFLAGS="${BASE_LINK_FLAGS} ${LDFLAGS:-}"
124}
125
126
127run_cmake() {
128    local cmake_args=(
129        -DCMAKE_C_COMPILER="${CC}"
130        -DCMAKE_C_FLAGS="${CFLAGS}"
131
132        -DCMAKE_CXX_COMPILER="${CXX}"
133        -DCMAKE_CXX_FLAGS="${CXXFLAGS}"
134
135        -DCMAKE_LINKER="${LD}"
136        -DCMAKE_EXE_LINKER_FLAGS="${LDFLAGS}"
137        -DCMAKE_MODULE_LINKER_FLAGS="${LDFLAGS}"
138        -DCMAKE_SHARED_LINKER_FLAGS="${LDFLAGS}"
139
140        -DEXPAT_WARNINGS_AS_ERRORS=ON
141    )
142    RUN cmake "${cmake_args[@]}" "$@" .
143}
144
145
146run_compile() {
147    local make_args=(
148        VERBOSE=1
149        -j2
150    )
151
152    RUN "${MAKE}" "${make_args[@]}" clean all
153}
154
155
156run_tests() {
157    case "${QA_PROCESSOR}" in
158        egypt) return 0 ;;
159    esac
160
161    if [[ ${CC} =~ mingw ]]; then
162        for i in tests xmlwf ; do
163            mingw32_dir="$(dirname "$(ls -1 /usr/lib*/gcc/i686-w64-mingw32/*/{libgcc_s_sjlj-1.dll,libstdc++-6.dll} | head -n1)")"
164            RUN ln -s \
165                    /usr/i686-w64-mingw32/lib/libwinpthread-1.dll \
166                    "${mingw32_dir}"/libgcc_s_dw2-1.dll \
167                    "${mingw32_dir}"/libgcc_s_sjlj-1.dll \
168                    "${mingw32_dir}"/libstdc++-6.dll \
169                    "$PWD"/libexpat{,w}-*.dll \
170                    ${i}/
171        done
172    fi
173
174    local make_args=(
175        CTEST_OUTPUT_ON_FAILURE=1
176        CTEST_PARALLEL_LEVEL=2
177        VERBOSE=1
178        test
179    )
180    [[ $* =~ -DEXPAT_DTD=OFF ]] || make_args+=( run-xmltest )
181
182    RUN "${MAKE}" "${make_args[@]}"
183}
184
185
186run_processor() {
187    if [[ ${QA_COMPILER} != gcc ]]; then
188        return 0
189    fi
190
191    case "${QA_PROCESSOR}" in
192    egypt)
193        local DOT_FORMAT="${DOT_FORMAT:-svg}"
194        local o="callgraph.${DOT_FORMAT}"
195        ANNOUNCE "egypt ...... | dot ...... > ${o}"
196        find . -name '*.expand' \
197                | sort \
198                | xargs -r egypt \
199                | unflatten -c 20 \
200                | dot -T${DOT_FORMAT} -Grankdir=LR \
201                > "${o}"
202        ;;
203    gcov)
204        for gcov_dir in lib xmlwf ; do
205        (
206            cd "${gcov_dir}" || exit 1
207            for gcda_file in $(find . -name '*.gcda' | sort) ; do
208                RUN gcov -s .libs/ ${gcda_file}
209            done
210        )
211        done
212
213        RUN find . -name '*.gcov' | sort
214        ;;
215    esac
216}
217
218
219run() {
220    populate_environment
221    dump_config
222
223    run_cmake "$@"
224    run_compile
225    run_tests "$@"
226    run_processor
227}
228
229
230dump_config() {
231    cat <<EOF
232Configuration:
233  QA_COMPILER=${QA_COMPILER}  # auto-detected from \$CC and \$CXX
234  QA_PROCESSOR=${QA_PROCESSOR}  # GCC only
235  QA_SANITIZER=${QA_SANITIZER}
236
237  CFLAGS=${CFLAGS}
238  CXXFLAGS=${CXXFLAGS}
239  LDFLAGS=${LDFLAGS}
240
241  CC=${CC}
242  CXX=${CXX}
243  LD=${LD}
244  MAKE=${MAKE}
245
246Compiler (\$CC):
247EOF
248    "${CC}" --version | sed 's,^,  ,'
249    echo
250}
251
252
253classify_compiler() {
254    local i
255    for i in "${CC:-}" "${CXX:-}"; do
256        [[ "$i" =~ clang ]] && { echo clang ; return ; }
257    done
258    echo gcc
259}
260
261
262process_config() {
263    case "${QA_COMPILER:=$(classify_compiler)}" in
264        clang|gcc) ;;
265        *) usage; exit 1 ;;
266    esac
267
268
269    if [[ ${QA_COMPILER} != gcc && -n ${QA_PROCESSOR:-} ]]; then
270        WARNING "QA_COMPILER=${QA_COMPILER} is not 'gcc' -- ignoring QA_PROCESSOR=${QA_PROCESSOR}"
271    fi
272
273    case "${QA_PROCESSOR:=gcov}" in
274        egypt|gcov) ;;
275        *) usage; exit 1 ;;
276    esac
277
278
279    if [[ ${QA_COMPILER} != clang && ( ${QA_SANITIZER:-} == cfi || ${QA_SANITIZER:-} == memory ) ]]; then
280        WARNING "QA_COMPILER=${QA_COMPILER} is not 'clang' -- ignoring QA_SANITIZER=${QA_SANITIZER}" >&2
281        QA_SANITIZER=
282    fi
283
284    case "${QA_SANITIZER:=address}" in
285        address|cfi|memory|undefined) ;;
286        *) usage; exit 1 ;;
287    esac
288}
289
290
291usage() {
292    cat <<"EOF"
293Usage:
294  $ ./qa.sh [ARG ..]
295
296Environment variables
297  QA_COMPILER=(clang|gcc)                      # default: auto-detected
298  QA_PROCESSOR=(egypt|gcov)                    # default: gcov
299  QA_SANITIZER=(address|cfi|memory|undefined)  # default: address
300
301EOF
302}
303
304
305main() {
306    if [[ ${1:-} = --help ]]; then
307        usage; exit 0
308    fi
309
310    process_config
311
312    run "$@"
313}
314
315
316main "$@"
317