| #! /usr/bin/env bash |
| # __ __ _ |
| # ___\ \/ /_ __ __ _| |_ |
| # / _ \\ /| '_ \ / _` | __| |
| # | __// \| |_) | (_| | |_ |
| # \___/_/\_\ .__/ \__,_|\__| |
| # |_| XML parser |
| # |
| # Copyright (c) 2016-2021 Sebastian Pipping <sebastian@pipping.org> |
| # Copyright (c) 2019 Philippe Antoine <contact@catenacyber.fr> |
| # Copyright (c) 2019 Hanno Böck <hanno@gentoo.org> |
| # Licensed under the MIT license: |
| # |
| # Permission is hereby granted, free of charge, to any person obtaining |
| # a copy of this software and associated documentation files (the |
| # "Software"), to deal in the Software without restriction, including |
| # without limitation the rights to use, copy, modify, merge, publish, |
| # distribute, sublicense, and/or sell copies of the Software, and to permit |
| # persons to whom the Software is furnished to do so, subject to the |
| # following conditions: |
| # |
| # The above copyright notice and this permission notice shall be included |
| # in all copies or substantial portions of the Software. |
| # |
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
| # NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
| # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
| # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
| # USE OR OTHER DEALINGS IN THE SOFTWARE. |
| |
| set -e |
| set -o nounset |
| |
| |
| ANNOUNCE() { |
| local open='\e[1m' |
| local close='\e[0m' |
| |
| echo -e -n "${open}" >&2 |
| echo -n "# $*" >&2 |
| echo -e "${close}" >&2 |
| } |
| |
| |
| WARNING() { |
| local open='\e[1;33m' |
| local close='\e[0m' |
| |
| echo -e -n "${open}" >&2 |
| echo -n "WARNING: $*" >&2 |
| echo -e "${close}" >&2 |
| } |
| |
| |
| RUN() { |
| ANNOUNCE "$@" |
| env "$@" |
| } |
| |
| |
| populate_environment() { |
| : ${MAKE:=make} |
| |
| case "${QA_COMPILER}" in |
| clang) |
| : ${CC:=clang} |
| : ${CXX:=clang++} |
| : ${LD:=clang++} |
| ;; |
| gcc) |
| : ${CC:=gcc} |
| : ${CXX:=g++} |
| : ${LD:=ld} |
| ;; |
| esac |
| |
| : ${BASE_COMPILE_FLAGS:="-pipe -Wall -Wextra -pedantic -Wno-overlength-strings -Wno-long-long"} |
| : ${BASE_LINK_FLAGS:=} |
| |
| if [[ ${QA_COMPILER} = clang ]]; then |
| case "${QA_SANITIZER}" in |
| address) |
| # http://clang.llvm.org/docs/AddressSanitizer.html |
| BASE_COMPILE_FLAGS+=" -g -fsanitize=address -fno-omit-frame-pointer -fno-common" |
| BASE_LINK_FLAGS+=" -g -fsanitize=address" |
| # macOS's XCode does not support LeakSanitizer and reports error: |
| # AddressSanitizer: detect_leaks is not supported on this platform. |
| if [[ "$(uname -s)" != Darwin* ]]; then |
| export ASAN_OPTIONS=detect_leaks=1 |
| fi |
| ;; |
| memory) |
| # http://clang.llvm.org/docs/MemorySanitizer.html |
| BASE_COMPILE_FLAGS+=" -fsanitize=memory -fno-omit-frame-pointer -g -O2 -fsanitize-memory-track-origins -fsanitize-blacklist=$PWD/memory-sanitizer-blacklist.txt" |
| ;; |
| undefined) |
| # http://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html |
| BASE_COMPILE_FLAGS+=" -fsanitize=undefined" |
| BASE_LINK_FLAGS+=" -fsanitize=undefined" |
| export UBSAN_OPTIONS="print_stacktrace=1:halt_on_error=1:abort_on_error=1" |
| ;; |
| esac |
| fi |
| |
| |
| if [[ ${QA_COMPILER} = gcc ]]; then |
| case "${QA_PROCESSOR}" in |
| egypt) BASE_COMPILE_FLAGS+=" -fdump-rtl-expand" ;; |
| gcov) BASE_COMPILE_FLAGS+=" --coverage -O0" ;; |
| esac |
| fi |
| |
| |
| CFLAGS="-std=c99 ${BASE_COMPILE_FLAGS} ${CFLAGS:-}" |
| CXXFLAGS="-std=c++98 ${BASE_COMPILE_FLAGS} ${CXXFLAGS:-}" |
| LDFLAGS="${BASE_LINK_FLAGS} ${LDFLAGS:-}" |
| } |
| |
| |
| run_cmake() { |
| local cmake_args=( |
| -DCMAKE_C_COMPILER="${CC}" |
| -DCMAKE_C_FLAGS="${CFLAGS}" |
| |
| -DCMAKE_CXX_COMPILER="${CXX}" |
| -DCMAKE_CXX_FLAGS="${CXXFLAGS}" |
| |
| -DCMAKE_LINKER="${LD}" |
| -DCMAKE_EXE_LINKER_FLAGS="${LDFLAGS}" |
| -DCMAKE_MODULE_LINKER_FLAGS="${LDFLAGS}" |
| -DCMAKE_SHARED_LINKER_FLAGS="${LDFLAGS}" |
| |
| -DEXPAT_WARNINGS_AS_ERRORS=ON |
| ) |
| RUN cmake "${cmake_args[@]}" "$@" . |
| } |
| |
| |
| run_compile() { |
| local make_args=( |
| VERBOSE=1 |
| -j2 |
| ) |
| |
| RUN "${MAKE}" "${make_args[@]}" clean all |
| } |
| |
| |
| run_tests() { |
| case "${QA_PROCESSOR}" in |
| egypt) return 0 ;; |
| esac |
| |
| if [[ ${CC} =~ mingw ]]; then |
| # NOTE: Filenames are hardcoded for Travis' Ubuntu Bionic, as of now |
| for i in tests xmlwf ; do |
| mingw32_dir="$(ls -1d /usr/lib/gcc/i686-w64-mingw32/* | head -n1)" |
| RUN ln -s \ |
| /usr/i686-w64-mingw32/lib/libwinpthread-1.dll \ |
| "${mingw32_dir}"/libgcc_s_sjlj-1.dll \ |
| "${mingw32_dir}"/libstdc++-6.dll \ |
| "$PWD"/libexpat{,w}.dll \ |
| ${i}/ |
| done |
| fi |
| |
| local make_args=( |
| CTEST_OUTPUT_ON_FAILURE=1 |
| CTEST_PARALLEL_LEVEL=2 |
| VERBOSE=1 |
| test |
| ) |
| [[ $* =~ -DEXPAT_DTD=OFF ]] || make_args+=( run-xmltest ) |
| |
| RUN "${MAKE}" "${make_args[@]}" |
| } |
| |
| |
| run_processor() { |
| if [[ ${QA_COMPILER} != gcc ]]; then |
| return 0 |
| fi |
| |
| case "${QA_PROCESSOR}" in |
| egypt) |
| local DOT_FORMAT="${DOT_FORMAT:-svg}" |
| local o="callgraph.${DOT_FORMAT}" |
| ANNOUNCE "egypt ...... | dot ...... > ${o}" |
| find -name '*.expand' \ |
| | sort \ |
| | xargs -r egypt \ |
| | unflatten -c 20 \ |
| | dot -T${DOT_FORMAT} -Grankdir=LR \ |
| > "${o}" |
| ;; |
| gcov) |
| for gcov_dir in lib xmlwf ; do |
| ( |
| cd "${gcov_dir}" || exit 1 |
| for gcda_file in $(find . -name '*.gcda' | sort) ; do |
| RUN gcov -s .libs/ ${gcda_file} |
| done |
| ) |
| done |
| |
| RUN find -name '*.gcov' | sort |
| ;; |
| esac |
| } |
| |
| |
| run() { |
| populate_environment |
| dump_config |
| |
| run_cmake "$@" |
| run_compile |
| run_tests "$@" |
| run_processor |
| } |
| |
| |
| dump_config() { |
| cat <<EOF |
| Configuration: |
| QA_COMPILER=${QA_COMPILER} # auto-detected from \$CC and \$CXX |
| QA_PROCESSOR=${QA_PROCESSOR} # GCC only |
| QA_SANITIZER=${QA_SANITIZER} # Clang only |
| |
| CFLAGS=${CFLAGS} |
| CXXFLAGS=${CXXFLAGS} |
| LDFLAGS=${LDFLAGS} |
| |
| CC=${CC} |
| CXX=${CXX} |
| LD=${LD} |
| MAKE=${MAKE} |
| |
| Compiler (\$CC): |
| EOF |
| "${CC}" --version | sed 's,^, ,' |
| echo |
| } |
| |
| |
| classify_compiler() { |
| local i |
| for i in "${CC:-}" "${CXX:-}"; do |
| [[ "$i" =~ clang ]] && { echo clang ; return ; } |
| done |
| echo gcc |
| } |
| |
| |
| process_config() { |
| case "${QA_COMPILER:=$(classify_compiler)}" in |
| clang|gcc) ;; |
| *) usage; exit 1 ;; |
| esac |
| |
| |
| if [[ ${QA_COMPILER} != gcc && -n ${QA_PROCESSOR:-} ]]; then |
| WARNING "QA_COMPILER=${QA_COMPILER} is not 'gcc' -- ignoring QA_PROCESSOR=${QA_PROCESSOR}" |
| fi |
| |
| case "${QA_PROCESSOR:=gcov}" in |
| egypt|gcov) ;; |
| *) usage; exit 1 ;; |
| esac |
| |
| |
| if [[ ${QA_COMPILER} != clang && -n ${QA_SANITIZER:-} ]]; then |
| WARNING "QA_COMPILER=${QA_COMPILER} is not 'clang' -- ignoring QA_SANITIZER=${QA_SANITIZER}" >&2 |
| fi |
| |
| case "${QA_SANITIZER:=address}" in |
| address|memory|undefined) ;; |
| *) usage; exit 1 ;; |
| esac |
| } |
| |
| |
| usage() { |
| cat <<"EOF" |
| Usage: |
| $ ./qa.sh [ARG ..] |
| |
| Environment variables |
| QA_COMPILER=(clang|gcc) # default: auto-detected |
| QA_PROCESSOR=(egypt|gcov) # default: gcov |
| QA_SANITIZER=(address|memory|undefined) # default: address |
| |
| EOF |
| } |
| |
| |
| main() { |
| if [[ ${1:-} = --help ]]; then |
| usage; exit 0 |
| fi |
| |
| process_config |
| |
| run "$@" |
| } |
| |
| |
| main "$@" |