#!/bin/sh
#
# Copyright (c) 2020-now by the Zeek Project. See LICENSE for details.
#
# Convenience wrapper for easily viewing/setting options that
# the project's CMake scripts will recognize
#
# Adapted from Zeek's wrapper.

set -e

# Defaults
cmake_binary_packaging_mode="no"
cmake_bison_root=""
cmake_build_directory="build"
cmake_build_shared_libs="yes"
cmake_build_toolchain="yes"
cmake_build_type="Release"
cmake_c_compiler=""
cmake_cxx_compiler=""
cmake_clang_tidy=""
cmake_flex_root=""
cmake_generator=""
cmake_install_prefix="/usr/local"
cmake_use_ccache="no"
cmake_use_gold="yes"
cmake_use_precompiled_headers="yes"
cmake_use_sanitizers=""
cmake_use_werror="no"

display_cmake=0
cmake_cache_entries=""

set -e
command="$0 $*"

cmake_exe="<no cmake>"
for i in cmake cmake3; do
    if which $i >/dev/null; then
        version="$($i --version 2>&1 | grep "cmake.*version" | awk -F '[ .]' '{print $3}')"
        test -n "${version}" && test "${version}" -ge 3 && cmake_exe=$(which $i)
        break
    fi
done

which "${cmake_exe}" > /dev/null 2>&1 || {
    echo "\
This package requires CMake >= 3, please install it first, then you may
use this configure script to access CMake equivalent functionality.\
" >&2;
    exit 1;
}

usage="\
Usage: $0 [OPTION]... [VAR=VALUE]...

  Build Options:
    --binary-package                      Toggle special logic for binary packaging
    --build-dir=DIR                       Place build files in directory [default: ${cmake_build_directory}]
    --build-static-libs                   Build static libraries instead [default: shared]
    --build-toolchain={yes,no}            Build the Spicy compiler toolchain [default: ${cmake_build_toolchain}]
    --build-type=TYPE                     Set build type (Debug,Release,RelWithDebInfo) [default: ${cmake_build_type}]
    --disable-gold                        On Linux, do not try to use the gold linker
    --disable-precompiled-headers         Disable use of precompiled headers for developer tests
    --disable-tests                       Disable building of tests and benchmarks
    --enable-ccache                       Build using the compiler cache cache if in PATH [default: ${cmake_use_ccache}]
    --enable-debug                        Compile debug version (same as --build-type=Debug) [default: off]
    --enable-clang-tidy                   Run clang-tidy from PATH during compilation [default: off]
    --enable-sanitizer[=<names>]          Enable sanitizer(s), default if not further specified is \"address\"
    --enable-werror                       Treat compiler warnings as errors [default: ${cmake_use_werror}]
    --generator=<generator>               CMake generator to use (see cmake --help)
    --prefix=PATH                         Installation prefix [default: ${cmake_install_prefix}]
    --with-bison=<prefix>                 Set prefix of Bison installation
    --with-c-compiler=<path>              Set C compiler to use
    --with-clang-tidy=<path>              Set clang-tidy binary and enable use during compilation
    --with-cxx-compiler=<path>            Set C++ compiler to use
    --with-hilti-compiler-launcher=<cmd>  Set compiler launcher to use during JIT, e.g., ccache.
    --with-flex=<prefix>                  Set prefix of Flex installation

    --display-cmake                       Don't create build configuration, just output final CMake invocation
"
source_dir="$(cd "$(dirname "$0")" && pwd)"

if [ ! -e "$source_dir/3rdparty/doctest/CMakeLists.txt" ] && [ -d "$source_dir/.git" ]; then
    echo "\
You seem to be missing the content of the 3rdparty/doctest directory.

This typically means that you performed a non-recursive git clone of
Spicy. To check out the required subdirectories, please execute:

  ( cd $source_dir && git submodule update --recursive --init )
" >&2;
    exit 1;
fi

# Function to append a CMake cache entry definition to the
# cmake_cache_entries variable.
#   $1 is the cache entry variable name
#   $2 is the cache entry variable type
#   $3 is the cache entry variable value
append_cache_entry () {
    if [ "$3" != "" ]; then
        cmake_cache_entries="${cmake_cache_entries} -D $1:$2=$3"
    fi
}

# parse arguments
while [ $# -ne 0 ]; do
    case "$1" in
        -*=*) optarg=$(echo "$1" | sed 's/[-_a-zA-Z0-9]*=//') ;;
        *) optarg= ;;
    esac

    case "$1" in
        --binary-package)                  cmake_binary_packaging_mode="yes";;
        --build-dir=*|--builddir=*)        cmake_build_directory="${optarg}";;
        --build-static-libs)               cmake_build_shared_libs="no";;
        --build-toolchain=*)               cmake_build_toolchain="${optarg}";;
        --build-type=*)                    cmake_build_type="${optarg}";;
        --disable-gold)                    cmake_use_gold="no";;
        --disable-precompiled-headers)     cmake_use_precompiled_headers="no";;
        --disable-tests)                   cmake_spicy_enable_tests="no";;
        --enable-ccache)                   cmake_use_ccache="yes";;
        --enable-debug)                    cmake_build_type="Debug";;
        --enable-clang-tidy)
            if ! which clang-tidy >/dev/null 2>&1; then
                echo "Error: clang-tidy not found in PATH" >&2
                exit 1
            fi

            cmake_clang_tidy="$(which clang-tidy)"
        ;;

        --enable-sanitizer)                cmake_use_sanitizers="address";;
        --enable-sanitizer=*)              cmake_use_sanitizers="${optarg}";;
        --enable-werror)                   cmake_use_werror="yes";;
        --generator=*)                     cmake_generator="${optarg}";;
        --prefix=*)                        cmake_install_prefix="${optarg}";;
        --with-c-compiler=*)               cmake_c_compiler="${optarg}";;
        --with-cxx-compiler=*)
            cmake_cxx_compiler="${optarg}"

            if [ -z "${cmake_c_compiler}" ]; then
              try_c_compiler=$(echo "${cmake_cxx_compiler}" | sed 's/++//g')
              which "${try_c_compiler}" >/dev/null && cmake_c_compiler="${try_c_compiler}"
            fi
            ;;

        --with-hilti-compiler-launcher=*)  hilti_compiler_launcher="${optarg}";;

        --with-clang-tidy=*)               cmake_clang_tidy="${optarg}";;
        --with-flex=*)                     cmake_flex_root="${optarg}";;
        --with-bison=*)                    cmake_bison_root="${optarg}";;
        --without-bison=*)                 cmake_bison_root="";;
        --without-flex=*)                  cmake_flex_root="";;

        --display-cmake) display_cmake=1;;

        --help|-h) echo "${usage}" 1>&2 && exit 1;;
        *) echo "Invalid option '$1'.  Try $0 --help to see available options." && exit 1;;
    esac
    shift
done

# Set CMake cache options.
append_cache_entry BINARY_PACKAGING_MODE        BOOL   "${cmake_binary_packaging_mode}"
append_cache_entry BISON_ROOT                   PATH   "${cmake_bison_root}"
append_cache_entry BUILD_SHARED_LIBS            BOOL   "${cmake_build_shared_libs}"
append_cache_entry BUILD_TOOLCHAIN              BOOL   "${cmake_build_toolchain}"
append_cache_entry CMAKE_BUILD_TYPE             STRING "${cmake_build_type}"
append_cache_entry CMAKE_C_COMPILER             PATH   "${cmake_c_compiler}"
append_cache_entry CMAKE_CXX_COMPILER           PATH   "${cmake_cxx_compiler}"
append_cache_entry CMAKE_C_CLANG_TIDY           PATH   "${cmake_clang_tidy}"
append_cache_entry CMAKE_CXX_CLANG_TIDY         PATH   "${cmake_clang_tidy}"
append_cache_entry CMAKE_INSTALL_PREFIX         PATH   "${cmake_install_prefix}"
append_cache_entry HILTI_COMPILER_LAUNCHER      STRING "${hilti_compiler_launcher}"
append_cache_entry FLEX_ROOT                    PATH   "${cmake_flex_root}"
append_cache_entry USE_CCACHE                   BOOL   "${cmake_use_ccache}"
append_cache_entry USE_GOLD                     BOOL   "${cmake_use_gold}"
append_cache_entry USE_SANITIZERS               STRING "${cmake_use_sanitizers}"
append_cache_entry HILTI_DEV_PRECOMPILE_HEADERS BOOL   "${cmake_use_precompiled_headers}"
append_cache_entry USE_WERROR                   BOOL   "${cmake_use_werror}"
append_cache_entry SPICY_ENABLE_TESTS           BOOL   "${cmake_spicy_enable_tests}"

if [ -n "${cmake_generator}" ]; then
    cmake="${cmake_exe} -G '${cmake_generator}' ${cmake_cache_entries} ${source_dir}"
else
    cmake="${cmake_exe} ${cmake_cache_entries} ${source_dir}"
fi

if [ "${display_cmake}" = 1 ]; then
    echo "${cmake}"
    exit 0
fi

if [ ! -d "${cmake_build_directory}" ]; then
    # Create build directory
    mkdir -p "${cmake_build_directory}"
else
    # If build directory already exists, remove any pre-existing
    # CMake cache so that this configuration is not tainted by a
    # previous one
    rm -f "${cmake_build_directory}"/CMakeCache.txt
fi

cd "${cmake_build_directory}"
fail=$(mktemp)
{ eval "${cmake}" 2>&1 || echo > "$fail"; } | tee config.log &&  [ ! -s "$fail" ]
rm "$fail"

echo "# This is the command used to configure this build" > config.status
echo "${command}" >> config.status
chmod u+x config.status
