#!/bin/bash
#
# This helper script is supposed to be executed from a build directory
# and sets CMake options depending on  the name of the directory.  The
# build directory shall be called
#
#     build.feature1-feature2-...
#
# Reconized features can be found  below.  Note that this mechanism is
# comparable to the _presets_ mechanism of recent CMake versions.

build_type=RelWithDebInfo
generator=Ninja
export CC=
export CXX=
opts=
cmake=cmake

config=$(basename $(pwd))

# gcc-version
# clang-version
#
# Set the compiler

case $config in
  *gcc-*)
    version=$(echo $config | sed 's/.*gcc-\(\(mp-\)\{0,1\}[0-9]*\).*/\1/')
    export CC=gcc-$version
    export CXX=g++-$version
    ;;
  *clang-[0-9]*)
    version=$(echo $config | sed 's/.*clang-\([0-9]*\).*/\1/')
    export CC=clang-$version
    export CXX=clang++-$version
    ;;
  *clang*)
    export CC=clang
    export CXX=clang++
    ;;
esac

# nogmp
# libbf
#
# Use LibBF rather than LibGMP for unbounded integers, rationals and random

case $config in
  *nogmp*|*libbf*)
    opts+=" -DUSE_GMP=OFF"
    ;;
esac

# single
#
# Build the single threaded version

case $config in
  *single*)
    opts+=" -DMULTI_THREADED=OFF"
    ;;
esac

# vmif
#
# Implement VMI instructions as functions.  Slower on GCC, about
# equal for Clang (and WASM) and much faster for MSVC

case $config in
  *vmif*)
    opts+=" -DVMI_FUNCTIONS=ON"
    ;;
esac

# profile
#
# Use good settings for valgrind based profiling

case $config in
  *profile*)
    opts+=" -DVMI_FUNCTIONS=ON"
    CFLAGS+=" -fno-inline"
    ;;
esac

# c11
#
# Enable pedantic C11 checking for GCC.  Use for compliancy testing as
# it  forces a  less  efficient virtual  machine due  to  the lack  of
# support for empty structures in C11.

case $config in
  *c11*)
    CFLAGS+=" -pedantic -DPEDANTIC"
    ;;
esac

# c23
#
# Enable C23 mode

case $config in
  *c23*)
    CFLAGS+=" -std=gnu23"
    ;;
esac

# test
#
# Install the  tests along  with the  executable.  Allows  running the
# tests in the installed version using test_installation/0.

case $config in
  *test*)
    opts+=" -DINSTALL_TESTS=ON"
    ;;
esac

# PDF docs
#
# Build the PDF documentation

case $config in
  *pdf*)
    opts+=" -DBUILD_PDF_DOCUMENTATION=ON"
    ;;
esac

# native tuning
#
# Optimize for local CPU

case $config in
  *native*)
    CFLAGS+=" -mtune=native -march=native"
    ;;
esac

# malloc
#
# Use  malloc  instead  of  tcmalloc.  Currently  required  for  using
# valgrind.  Do not use on  Linux builds aiming at 24x7 multi-threaded
# services: ptmalloc seems poor at reusing memory in these workloads.

case $config in
  *malloc*)
    opts+=" -DUSE_TCMALLOC=OFF"
    ;;
esac

# pgo
# debug
# asan
#
# Select the  build type.  PGO  provides best performance.   Use debug
# for C level debugging and asan for leak and memory issue detection.

case $config in
  *pgo*)
    build_type=PGO
    ;;
  *debug*)
    build_type=Debug
    ;;
  *asan*)
    build_type=Sanitize
    ;;
  *ubsan*)
    build_type=Sanitize
    opts+=" -DSANITIZE=undefined"
    ;;
esac

# wasm
# termux
#
# Build for specific targets

case $config in
    *wasm*)
	WASM_HOME=$HOME/wasm
	source $WASM_HOME/emsdk/emsdk_env.sh
	TOOLCHAIN=$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake
	[ -f $TOOLCHAIN ] || echo "Could not find emscripten toolchain"
	cmake="emcmake cmake"
	build_type=Release
	LDFLAGS+=" -s STACK_SIZE=1048576"
	opts+=" -DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN"
	opts+=" -DCMAKE_FIND_ROOT_PATH=$HOME/wasm"
	opts+=" -DUSE_GMP=OFF"
	opts+=" -DINSTALL_DOCUMENTATION=OFF"
	;;
    *termux*)
	opts+=" -DPOSIX_SHELL=${PREFIX}/bin/sh"
	opts+=" -DSWIPL_TMP_DIR=${PREFIX}/tmp"
	opts+=" -DSYSTEM_CACERT_FILENAME=${PREFIX}/etc/tls/cert.pem"
	;;
esac

function confirm ()
{ while true; do
    echo -n "$1 "
    read answer
    case "$answer" in
          y*)   return 0
                ;;
          n*)   return 1
                ;;
          *)
                echo "Please answer yes or no"
                ;;
    esac
  done
}

export CFLAGS
export LDFLAGS

using=
[ -z "$CC" ]      || using+=" "CC=$CC
[ -z "$CXX" ]     || using+=" "CXX=$CXX
[ -z "$CFLAGS" ]  || using+=" "CFLAGS='"'$CFLAGS'"'
[ -z "$LDFLAGS" ] || using+=" "LDFLAGS='"'$LDFLAGS'"'

cat << EOF
# Configure using
#
#    $using cmake -DCMAKE_BUILD_TYPE=$build_type -G $generator $opts ..
#
EOF

if ! confirm "Run Cmake? "; then
  exit 1
fi

cat > configure << EOF
# Created by ../scripts/configure for $config at $(date)

$using $cmake -DCMAKE_BUILD_TYPE=$build_type -G $generator $opts ..
EOF
chmod +x configure

# Create direnv file.  We need this to avoid resetting variables
# when re-running cmake
[ -z "$CC" ]      || echo "export CC=$CC"                  > .envrc
[ -z "$CXX" ]     || echo "export CXX=$CXX"               >> .envrc
[ -z "$CFLAGS" ]  || echo "export CFLAGS="'"'$CFLAGS'"'   >> .envrc
[ -z "$LDFLAGS" ] || echo "export LDFLAGS="'"'$LDFLAGS'"' >> .envrc

./configure
