#! /usr/bin/env bash # Copyright (C) 2016 Sebastian Pipping # Licensed under MIT license 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 -Wc,-fsanitize=address" # "-Wc," is for libtool ;; 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_configure() { RUN CC="${CC}" CFLAGS="${CFLAGS}" \ CXX="${CXX}" CXXFLAGS="${CXXFLAGS}" \ LD="${LD}" LDFLAGS="${LDFLAGS}" \ ./configure "$@" \ || { RUN cat config.log ; false ; } } run_compile() { RUN "${MAKE}" \ CFLAGS="${CFLAGS} -Werror" \ CXXFLAGS="${CXXFLAGS} -Werror" \ clean all } run_tests() { case "${QA_PROCESSOR}" in egypt) return 0 ;; esac if [[ ${CC} =~ mingw ]]; then # NOTE: Filenames are hardcoded for Travis Ubuntu trusty, as of now for i in tests xmlwf xmlwf/.libs ; do RUN ln -s \ /usr/i686-w64-mingw32/lib/libwinpthread-1.dll \ /usr/lib/gcc/i686-w64-mingw32/4.8/libgcc_s_sjlj-1.dll \ /usr/lib/gcc/i686-w64-mingw32/4.8/libstdc++-6.dll \ ../lib/.libs/libexpat-1.dll \ ${i}/ done fi RUN "${MAKE}" \ CFLAGS="${CFLAGS} -Werror" \ CXXFLAGS="${CXXFLAGS} -Werror" \ check run-xmltest \ || { RUN cat tests/runtests.log RUN cat tests/runtestspp.log false } } 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_configure "$@" run_compile run_tests run_processor } dump_config() { cat <&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: gcc 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 "$@"