| #!/usr/bin/env bash |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| MYDIR=$(dirname $(realpath "$0")) |
| BUILD_DIR="${BUILD_DIR:-${MYDIR}/build}" |
|
|
| CMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE:-RelWithDebInfo}" |
| CMAKE_C_COMPILER="${CMAKE_C_COMPILER:-clang-14}" |
| CMAKE_CXX_COMPILER="${CMAKE_CXX_COMPILER:-clang++-14}" |
| |
| CMAKE_FLAGS="${CMAKE_FLAGS:-}" |
| CMAKE_C_FLAGS="${CMAKE_C_FLAGS:-} ${CMAKE_FLAGS}" |
| CMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS:-} ${CMAKE_FLAGS}" |
| CMAKE_EXE_LINKER_FLAGS="${CMAKE_EXE_LINKER_FLAGS:-}" |
| CMAKE_MODULE_LINKER_FLAGS="${CMAKE_MODULE_LINKER_FLAGS:-}" |
| CMAKE_SHARED_LINKER_FLAGS="${CMAKE_SHARED_LINKER_FLAGS:-}" |
|
|
| |
| UBSAN_FLAGS=( |
| -fsanitize=alignment |
| -fsanitize=bool |
| -fsanitize=bounds |
| -fsanitize=builtin |
| -fsanitize=enum |
| -fsanitize=float-cast-overflow |
| -fsanitize=float-divide-by-zero |
| -fsanitize=integer-divide-by-zero |
| -fsanitize=null |
| -fsanitize=object-size |
| -fsanitize=pointer-overflow |
| -fsanitize=return |
| -fsanitize=returns-nonnull-attribute |
| -fsanitize=shift-base |
| -fsanitize=shift-exponent |
| -fsanitize=unreachable |
| -fsanitize=vla-bound |
|
|
| -fno-sanitize-recover=undefined |
| -fsanitize-recover=alignment |
| ) |
|
|
| CLANG_VERSION="${CLANG_VERSION:-}" |
| |
| |
| detect_clang_version() { |
| if [[ -n "${CLANG_VERSION}" ]]; then |
| return 0 |
| fi |
| local clang_version=$("${CMAKE_C_COMPILER:-clang}" --version | head -n1) |
| clang_version=${clang_version#"Debian "} |
| clang_version=${clang_version#"Ubuntu "} |
| local llvm_tag |
| case "${clang_version}" in |
| "clang version 6."*) |
| CLANG_VERSION="6.0" |
| ;; |
| "clang version "*) |
| |
| local suffix="${clang_version#clang version }" |
| CLANG_VERSION="${suffix%%.*}" |
| ;; |
| "emcc"*) |
| |
| ;; |
| *) |
| echo "Unknown clang version: ${clang_version}" >&2 |
| return 1 |
| esac |
| } |
|
|
| |
| CLEANUP_FILES=() |
| cleanup() { |
| if [[ ${#CLEANUP_FILES[@]} -ne 0 ]]; then |
| rm -fr "${CLEANUP_FILES[@]}" |
| fi |
| } |
|
|
| |
| on_exit() { |
| local retcode="$1" |
| |
| cleanup |
| } |
|
|
| trap 'retcode=$?; { set +x; } 2>/dev/null; on_exit ${retcode}' INT TERM EXIT |
|
|
|
|
| |
| |
| cmd_msan_install() { |
| local tmpdir=$(mktemp -d) |
| CLEANUP_FILES+=("${tmpdir}") |
| |
| detect_clang_version |
| |
| local llvm_root="${LLVM_ROOT:-}" |
| if [ -z "${llvm_root}" ]; then |
| local llvm_tag="llvmorg-${CLANG_VERSION}.0.0" |
| case "${CLANG_VERSION}" in |
| "6.0") |
| llvm_tag="llvmorg-6.0.1" |
| ;; |
| "7") |
| llvm_tag="llvmorg-7.0.1" |
| ;; |
| esac |
| local llvm_targz="${tmpdir}/${llvm_tag}.tar.gz" |
| curl -L --show-error -o "${llvm_targz}" \ |
| "https://github.com/llvm/llvm-project/archive/${llvm_tag}.tar.gz" |
| tar -C "${tmpdir}" -zxf "${llvm_targz}" |
| llvm_root="${tmpdir}/llvm-project-${llvm_tag}" |
| fi |
|
|
| local msan_prefix="${HOME}/.msan/${CLANG_VERSION}" |
| rm -rf "${msan_prefix}" |
|
|
| declare -A CMAKE_EXTRAS |
| CMAKE_EXTRAS[libcxx]="\ |
| -DLIBCXX_CXX_ABI=libstdc++ \ |
| -DLIBCXX_INSTALL_EXPERIMENTAL_LIBRARY=ON \ |
| -DLIBCXX_INCLUDE_BENCHMARKS=OFF" |
|
|
| for project in libcxx; do |
| local proj_build="${tmpdir}/build-${project}" |
| local proj_dir="${llvm_root}/${project}" |
| mkdir -p "${proj_build}" |
| cmake -B"${proj_build}" -H"${proj_dir}" \ |
| -G Ninja \ |
| -DCMAKE_BUILD_TYPE=Release \ |
| -DLLVM_USE_SANITIZER=Memory \ |
| -DLLVM_PATH="${llvm_root}/llvm" \ |
| -DLLVM_CONFIG_PATH="$(which llvm-config llvm-config-7 llvm-config-6.0 | \ |
| head -n1)" \ |
| -DCMAKE_C_COMPILER="${CMAKE_C_COMPILER}" \ |
| -DCMAKE_CXX_COMPILER="${CMAKE_CXX_COMPILER}" \ |
| -DCMAKE_C_FLAGS="${CMAKE_C_FLAGS}" \ |
| -DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS}" \ |
| -DCMAKE_EXE_LINKER_FLAGS="${CMAKE_EXE_LINKER_FLAGS}" \ |
| -DCMAKE_SHARED_LINKER_FLAGS="${CMAKE_SHARED_LINKER_FLAGS}" \ |
| -DCMAKE_INSTALL_PREFIX="${msan_prefix}" \ |
| ${CMAKE_EXTRAS[${project}]} |
| cmake --build "${proj_build}" |
| ninja -C "${proj_build}" install |
| done |
| } |
|
|
| cmd_msan() { |
| detect_clang_version |
| local msan_prefix="${HOME}/.msan/${CLANG_VERSION}" |
| if [[ ! -d "${msan_prefix}" || -e "${msan_prefix}/lib/libc++abi.a" ]]; then |
| |
| |
| cmd_msan_install |
| fi |
|
|
| local msan_c_flags=( |
| -fsanitize=memory |
| -fno-omit-frame-pointer |
|
|
| -g |
| -DMEMORY_SANITIZER |
|
|
| |
| -DGTEST_HAS_CXXABI_H_=0 |
|
|
| -fsanitize-memory-track-origins |
| ) |
|
|
| local msan_cxx_flags=( |
| "${msan_c_flags[@]}" |
|
|
| |
| |
| -Wno-unused-command-line-argument |
| -stdlib=libc++ |
|
|
| |
| |
| -nostdinc++ |
| -cxx-isystem"${msan_prefix}/include/c++/v1" |
| ) |
|
|
| local msan_linker_flags=( |
| -L"${msan_prefix}"/lib |
| -Wl,-rpath -Wl,"${msan_prefix}"/lib/ |
| ) |
|
|
| CMAKE_C_FLAGS+=" ${msan_c_flags[@]} ${UBSAN_FLAGS[@]}" |
| CMAKE_CXX_FLAGS+=" ${msan_cxx_flags[@]} ${UBSAN_FLAGS[@]}" |
| CMAKE_EXE_LINKER_FLAGS+=" ${msan_linker_flags[@]}" |
| CMAKE_MODULE_LINKER_FLAGS+=" ${msan_linker_flags[@]}" |
| CMAKE_SHARED_LINKER_FLAGS+=" ${msan_linker_flags[@]}" |
| cmake_configure "$@" \ |
| -DCMAKE_CROSSCOMPILING=1 -DRUN_HAVE_STD_REGEX=0 -DRUN_HAVE_POSIX_REGEX=0 \ |
| -DCMAKE_REQUIRED_LINK_OPTIONS="${msan_linker_flags[@]}" |
| } |
|
|
| cmake_configure() { |
| local args=( |
| -B"${BUILD_DIR}" -H"${MYDIR}" |
| -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" |
| -G Ninja |
| -DCMAKE_C_COMPILER="${CMAKE_C_COMPILER}" |
| -DCMAKE_CXX_COMPILER="${CMAKE_CXX_COMPILER}" |
| -DCMAKE_C_FLAGS="${CMAKE_C_FLAGS}" |
| -DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS}" |
| -DCMAKE_EXE_LINKER_FLAGS="${CMAKE_EXE_LINKER_FLAGS}" |
| -DCMAKE_MODULE_LINKER_FLAGS="${CMAKE_MODULE_LINKER_FLAGS}" |
| -DCMAKE_SHARED_LINKER_FLAGS="${CMAKE_SHARED_LINKER_FLAGS}" |
| -DGEMMA_ENABLE_TESTS=ON |
| ) |
|
|
| cmake "${args[@]}" "$@" |
| } |
|
|
| cmd_opt() { |
| CMAKE_BUILD_TYPE="RelWithDebInfo" |
| cmake_configure "$@" |
| } |
|
|
| cmd_asan() { |
| CMAKE_C_FLAGS+=" -g -DADDRESS_SANITIZER -fsanitize=address ${UBSAN_FLAGS[@]}" |
| CMAKE_CXX_FLAGS+=" -g -DADDRESS_SANITIZER -fsanitize=address \ |
| ${UBSAN_FLAGS[@]}" |
| cmake_configure "$@" |
| } |
|
|
| cmd_tsan() { |
| SANITIZER="tsan" |
| local tsan_args=( |
| -g |
| -DTHREAD_SANITIZER |
| ${UBSAN_FLAGS[@]} |
| -fsanitize=thread |
| ) |
| CMAKE_C_FLAGS+=" ${tsan_args[@]}" |
| CMAKE_CXX_FLAGS+=" ${tsan_args[@]}" |
|
|
| CMAKE_BUILD_TYPE="RelWithDebInfo" |
| cmake_configure "$@" |
| } |
|
|
| main() { |
| local cmd="${1:-}" |
| if [[ -z "${cmd}" ]]; then |
| cat >&2 <<EOF |
| Use: $0 CMD |
| |
| Where cmd is one of: |
| opt Build and test a Release with symbols build. |
| asan Build and test an ASan (AddressSanitizer) build. |
| msan Build and test an MSan (MemorySanitizer) build. Needs to have msan |
| c++ libs installed with msan_install first. |
| msan_install Install the libc++ libraries required to build in msan mode. This |
| needs to be done once. |
| tsan Build and test a TSan (ThreadSanitizer) build. |
| |
| You can pass some optional environment variables as well: |
| - BUILD_DIR: The output build directory (by default "$$repo/build") |
| - CMAKE_FLAGS: Convenience flag to pass both CMAKE_C_FLAGS and CMAKE_CXX_FLAGS. |
| |
| These optional environment variables are forwarded to the cmake call as |
| parameters: |
| - CMAKE_BUILD_TYPE |
| - CMAKE_C_FLAGS |
| - CMAKE_CXX_FLAGS |
| - CMAKE_C_COMPILER |
| - CMAKE_CXX_COMPILER |
| - CMAKE_EXE_LINKER_FLAGS |
| - CMAKE_MODULE_LINKER_FLAGS |
| - CMAKE_SHARED_LINKER_FLAGS |
| |
| Example: |
| BUILD_DIR=/tmp/build $0 opt |
| EOF |
| exit 1 |
| fi |
|
|
| cmd="cmd_${cmd}" |
| shift |
| set -x |
| "${cmd}" "$@" |
| } |
|
|
| main "$@" |
|
|