#!/bin/bash
#
# Copyright (c) 2018-2020 The University of Tennessee and The University
#                         of Tennessee Research Foundation.  All rights
#                         reserved.

prefix=/usr/local
srcdir=${0%/*}
cmake_generator="Unix Makefiles"

# Be paranoid about errors and abort asap
set -e

function expand_relative_path {
  [[ ${1:0:1} = '/' ]] && echo "${1}" || echo "${PWD}/${1}"
}
srcdir="$(expand_relative_path $srcdir)"

function show_help_and_exit {
cat <<EOF
-h | --help
                show usage
-V
                version information
-q | --quiet | --silent
                no configure output to the console
-n | --no-create
                do not run the CMake phase

-DVAR=VALUE
                Directly pass VAR=VALUE to the Cmake configure stage
--
                The remainder of the command line arguments are sent to the Cmake configure stage as-is
--with-ninja[=DIR]
                Use Ninja to build to project


--with-platform=FILE
                source options specific for a target platform
--srcdir=DIR
                use DIR to find the source directory (default $srcdir)
--prefix=DIR
                install to the DIR directory (default $prefix)
--host=ARCH
                cross compile for the target ARCH architecture
--enable-doc
                Build the documentation (requires doxygen)
--enable-static
                build static libraries and executables
--enable-shared
                build dynamic libraries and executables
--enable-c11
                Enable C11 standard capabilities (may conflict with OpenMP)
--enable-cxx
                Enable CXX bindings
--enable-fortran
                Enable Fortran bindings


--enable-debug=yes,paranoid,noisier|history|no
                turn on debugging information
                    yes:            normal debugging; some overhead
                    paranoid:       more thorough assertions; extra overhead
                    noisier:        more verbose debugging; heavy overhead
                    history:        keep an history of latest debugging messages in memory for gdb printing; light overhead
                    no (explicit):  remove all debugging symbols and assertions

--enable-prof-trace
                produce a trace of the execution that can be analyzed in a trace vizualizer
--enable-prof-calltrace
                print a message when each task body is executed
--enable-prof-dryrun=yes|dep|body|no
                turn on 'dry-run' mode
                    dep:            communication is skipped (only task completion signaling messages are sent)
                    body:           computation is skipped (no task body execution)
                    yes:            both communication and computation are skipped
                    no:             normal execution
--enable-prof-grapher
                turn on grapher mode: generates the dependency graph instead of executing
--enable-testing
                enable the compilation of all PaRSEC tests

--with-tau[=DIR]
                use the TAU profiler package [installed in DIR]
--with-papi[=DIR]
                use the PAPI performance counter package [installed in DIR] (default=autodetect)
--with-gtg[=DIR]
                use the GTG package [installed in DIR] (optional)
--with-ayudame[=DIR]
                use the Ayudame package [installed in DIR] (optional)

--with-hwloc[=DIR]
                use the HWLoc package [installed in DIR] (default=autodetect)


--with-python[=DIR]
                use the Python interpreter [installed in DIR] (default=autodetect)
--enable-python-venv
                create a Python virtualenv that contains the dependencies for Parsec profiling tools (default=false)

--with-mpi[=DIR]
                use the MPI communication library [installed in DIR] (default=autodetect)
--enable-collectives
                use asynchronous dataflow collective communication


--with-cuda[=DIR]
                use the CUDA accelerator libray [installed in DIR] (default=autodetect)
--with-cuda-sm-targets=x,y,z
                compile kernels optimized for the CUDA SM model x, y and z
                where x,y,z are two digit numbers representing a valid CUDA architecture (e.g. 35,37,60) (default=autodetect)


Some influential environment variables:
  CC          C compiler command
  CFLAGS      C compiler flags
  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
              nonstandard directory <lib dir>
  LIBS        libraries to pass to the linker, e.g. -l<library>
  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
              you have headers in a nonstandard directory <include dir>
  CPP         C preprocessor
  CXX         C++ compiler command
  CXXFLAGS    C++ compiler flags
  CXXCPP      C++ preprocessor
  CCAS        assembler compiler command (defaults to CC)
  CCASFLAGS   assembler compiler flags (defaults to CFLAGS)
  FC          Fortran compiler command
  FCFLAGS     Fortran compiler flags
  CMAKE_EXECUTABLE
              Path to the CMake executable
  PKG_CONFIG  path to pkg-config utility
  PKG_CONFIG_PATH
              directories to add to pkg-config's search path
  PKG_CONFIG_LIBDIR
              path overriding pkg-config's built-in search path

Use these variables to override the choices made by 'configure' or to help
it to find libraries and programs with nonstandard names/locations.

Please report bugs to <https://bitbucket.org/icldistcomp/parsec/issues>

EOF
[ -z "$1" ] || cat >&2 <<EOF
#######################################################################
CONFIGURATION ERROR: $*
#######################################################################
EOF
exit 1
}

function show_version_and_exit {
echo "PaRSEC version $(git show --pretty='%h (%cd)')"
exit 2
}

function parse_early_arguments {
while [ "x$1" != x ]; do
    case "$1" in
        -h|--help) show_help_and_exit ;;
        -V) show_version_and_exit ;;
        -q|--quiet|--silent) quiet=yes; shift;;
        -n|--no-create) nocreate=yes; shift;;
        --srcdir=*) srcdir="$(printf %q "$(expand_relative_path "${1#*=}")")"; shift;;
        --prefix=*) prefix="$(printf %q "$(expand_relative_path "${1#*=}")")"; shift;;
        --host=*) host="${1#*=}"; shift;;
# Environment variables
        [^-]*=*) eval export $(printf %q "$1"); shift;;
        *) shift;;
    esac
done
}


function parse_arguments {
while [ "x$1" != x ]; do
    case "$1" in
        -h|--help) show_help_and_exit ;;
        -V) show_version_and_exit ;;
        -q|--quiet|--silent) quiet=yes; shift;;
        -n|--no-create) nocreate=yes; shift;;
        --srcdir=*) srcdir="$(printf %q "$(expand_relative_path "${1#*=}")")"; shift;;
        --prefix=*) prefix="$(printf %q "$(expand_relative_path "${1#*=}")")"; shift;;
        --host=*) host="${1#*=}"; shift;;
        --enable-static) enable_static=yes; shift;;
        --disable-static) enable_static=no; shift;;
        --enable-shared) enable_shared=yes; shift;;
        --disable-shared) enable_shared=no; shift;;
        --enable-c11) enable_c11=yes; shift;;
        --disable-c11) enable_c11=no; shift;;
        --enable-cxx) enable_cxx=yes; shift;;
        --disable-cxx) enable_cxx=no; shift;;
        --enable-fortran) enable_fortran=yes; shift;;
        --disable-fortran) enable_fortran=no; shift;;
        --enable-doc) enable_doc=yes; shift;;
        --disable-doc) enable_doc=no; shift;;
        --enable-testing) enable_testing=yes; shift;;
        --disable-testing) enable_testing=no; shift;;

#debug/profiling
        --enable-debug=*) enable_debug="${1#*=}"; shift;;
        --enable-debug) enable_debug=yes; shift;;
        --disable-debug) enable_debug=no; shift;;
        --enable-prof-trace) enable_prof_trace=yes; shift;;
        --disable-prof-trace) enable_prof_trace=no; shift;;
        --enable-prof-calltrace) enable_prof_calltrace=yes; shift;;
        --disable-prof-calltrace) enable_prof_calltrace=no; shift;;
        --enable-prof-dryrun=*) enable_prof_dryrun="${1#*=}"; shift;;
        --enable-prof-dryrun) enable_prof_dryrun=yes; shift;;
        --disable-prof-dryrun) enable_prof_dryrun=no; shift;;
        --enable-prof-grapher) enable_prof_grapher=yes; shift;;
        --disable-prof-grapher) enable_prof_grapher=no; shift;;
        --enable-prof-pins) enable_prof_pins=yes; shift;;
        --disable-prof-pins) enable_prof_pins=no; shift;;

        --with-tau=*) with_tau="${1#*=}"; shift;;
        --with-tau) with_tau=yes; shift;;
        --without-tau) with_tau=no; shift;;
        --with-papi=*) with_papi="${1#*=}"; shift;;
        --with-papi) with_papi=yes; shift;;
        --without-papi) with_papi=no; shift;;
        --with-gtg=*) with_gtg="${1#*=}"; shift;;
        --with-gtg) with_gtg=yes; shift;;
        --without-gtg) with_gtg=no; shift;;
        --with-ayudame=*) with_ayudame="${1#*=}"; shift;;
        --with-ayudame) with_ayudame=yes; shift;;
        --without-ayudame) with_ayudame=no; shift;;

# MPI options
        --with-mpi=*) with_mpi="${1#*=}"; shift;;
        --with-mpi) with_mpi=yes; shift;;
        --without-mpi) with_mpi=no; shift;;
        --enable-collectives) enable_collectives=yes; shift;;
        --disable-collectives) enable_collectives=no; shift;;

# Hwloc options
        --with-hwloc=*) with_hwloc="${1#*=}"; shift;;
        --with-hwloc) with_hwloc=yes; shift;;
        --without-hwloc) with_hwloc=no; shift;;

# Cuda options
        --with-cuda=*) with_cuda="${1#*=}"; shift;;
        --with-cuda) with_cuda=yes; shift;;
        --without-cuda) with_cuda=no; shift;;
        --with-cuda-sm-targets=*) with_cuda_sm_targets="${1#*=}"; shift;;
        --with-cuda-sm-targets) with_cuda_sm_targets=yes; shift;;
        --without-cuda-sm-targets) with_cuda_sm_targets=no; shift;;

# Python options
        --with-python=*) with_python="${1#*=}"; shift;;
        --with-python) with_python=yes; shift;;
        --without-python) with_python=no; shift;;
        --enable-python-venv) enable_python_venv=yes; shift;;
        --disable-python-venv) enable_python_venv=no; shift;;

# Ninja Generator
        --with-ninja=*) with_ninja="${1#*=}"; shift;;
        --with-ninja) with_ninja=yes; shift;;
        --without-ninja) with_ninja=no; shift;;

# Cmake passthrough
        -D*=*) CMAKE_DEFINES+=" $(printf %q "$1")"; shift;;
        --) shift;
            for param in "$@"; do
                CMAKE_DEFINES_RAW+=" $(printf %q "$param")";
            done;
            return;;

# Environment variables
        [^-]*=*) ENVVARS+=" $(printf %q "$1")"; shift;;

# Unhandled argument
        --with-platform=*) shift;; #already managed
        *) show_help_and_exit "Invalid argument: $1";;
    esac
done
}

function set_cmake_executable {
local cmake_executables cme
cmake_executables=${CMAKE_EXECUTABLE:-cmake cmake3}
set +e
for cme in ${cmake_executables}; do
    [ -d "$cme" ] && cme=$(PATH="$cme:$PATH" command -v cmake)
    cme="$(command -v "$cme")" # full-path
    [ -x "$cme" ] && break
    cme=''
done
set -e
cmake_executable=$cme
}

function read_platforms {
local varname i
for i in "$@"; do
    with_platform=${i#--with-platform=}
    [ "$i" = "$with_platform" ] && continue
    #echo "  parse_arguments $(sed 's/#.*$//' $with_platform | sed '/^$/d' | xargs -0 -d'\n' bash -c "printf %q")"
    if [ -r "$with_platform" ]; then
        . $with_platform
    elif [ -r "$srcdir/contrib/platforms/$with_platform" ]; then
        . $srcdir/contrib/platforms/$with_platform
    else
      show_help_and_exit "Platform file $with_platform not found"
    fi
    # convert disable/without_xxx to enable/with_xxx=no
    for varname in ${!disable_*}; do
      eval enable_${varname#*disable_}=no
    done
    for varname in ${!without_*}; do
      eval with_${varname#*without_}=no
    done
done
}

function set_python_venv {
    if [ -x "$(command -v virtualenv)" ]; then
        virtualenv --prompt='pyparsec> ' ${PYTHON_EXECUTABLE:+-p ${PYTHON_EXECUTABLE}} venv
        source venv/bin/activate
        pip install Cython pandas matplotlib tables
    else
        echo >&2 "Could not prepare a Python venv because \`virtualenv\` was not found... Continue with native Python."
    fi
}

#
# Cross compilation support helpers
#
# First prepare the native build, so we can use the tools on the headnode
# Prepare the native toolchain in directory $1
function configure_native_toolchain {
    # This is the list of named input parameters
    local NATIVE_DIR="${NATIVE_DIR:-$PWD/native}" NATIVE_CC="$NATIVE_CC" NATIVE_CFLAGS="$NATIVE_CFLAGS" NATIVE_CXX="$NATIVE_CXX" NATIVE_CXXFLAGS="$NATIVE_CXXFLAGS" NATIVE_LDFLAGS="$NATIVE_LDFLAGS"
    local NATIVE_PREFIX="${NATIVE_PREFIX:-$(expand_relative_path "${prefix}")}"
    local srcdir="${NATIVE_SRCDIR:-$(expand_relative_path "${srcdir}")}"
    local TOOLCHAIN_FILE=$1
    shift
    cat << _EOF
#   Cross-compiling toolchain will be found in
#     $NATIVE_DIR
#
_EOF
    mkdir -p "$NATIVE_DIR" && pushd "$NATIVE_DIR"
    rm -rf CMakeCache.txt CMakeFiles

    # Disable MPI, CUDA, HWLOC when creating the build-tools
    local NATIVE_MPI="-DPARSEC_DIST_WITH_MPI=OFF"
    local NATIVE_CUDA="-DPARSEC_GPU_WITH_CUDA=OFF"
    local NATIVE_HWLOC=""
    local NATIVE_COMPILERS="-DSUPPORT_FORTRAN=OFF"
    local NATIVE_OPTS="-DBUILD_TESTING=OFF -DBUILD_TOOLS=ON -DBUILD_PARSEC=ON -DCMAKE_INSTALL_PREFIX=$NATIVE_PREFIX $NATIVE_MPI $NATIVE_CUDA $NATIVE_HWLOC $NATIVE_COMPILERS"

    set_cmake_executable #may have been changed in the platform file
    echo "CC=\"${NATIVE_CC}\" CFLAGS=\"${NATIVE_CFLAGS}\" CXX=\"${NATIVE_CXX}\" CXXFLAGS=\"${NATIVE_CXXFLAGS}\" LDFLAGS=\"${NATIVE_LDFLAGS}\" ${cmake_executable} -G\"${cmake_generator}\" ${NATIVE_OPTS} ${PARSEC_TOOLCHAIN_OPTIONS} $(for i in "$@"; do printf ' %q' "$i"; done) ${srcdir}"
    CC="${NATIVE_CC}" CFLAGS="${NATIVE_CFLAGS}" CXX="${NATIVE_CXX}" CXXFLAGS="${NATIVE_CXXFLAGS}" LDFLAGS="${NATIVE_LDFLAGS}" ${cmake_executable} -G"${cmake_generator}" ${NATIVE_OPTS} ${PARSEC_TOOLCHAIN_OPTIONS} "$@" ${srcdir}
    popd
    [ -r "$TOOLCHAIN_FILE" ] || echo >&2 "Cross compiling Toolchain file TOOLCHAIN_FILE=$TOOLCHAIN_FILE is missing... This will probably cause an error."
    local TOOLCHAIN=" -DCMAKE_TOOLCHAIN_FILE=\"$TOOLCHAIN_FILE\" -DIMPORT_EXECUTABLES=\"$NATIVE_DIR/ImportExecutables.cmake\""
    CMAKE_DEFINES+=" -DBUILD_TOOLS=OFF $TOOLCHAIN"
}

# Compile the native tools in NATIVE_DIR
function build_native_toolchain {
    local NATIVE_DIR="$NATIVE_DIR"
    pushd "$NATIVE_DIR"
    cd tools && make install
    cd -
    cd parsec/interfaces/ptg && make install
    cd -
    popd
}

# Change CC CXX FC arch to match --host request
function host_adapt {
    [ -z $host ] && return
    arch=${host%%-*}
    local bcc=${CC##*/}
    local HOSTCC=$(command -v ${CC/%$bcc/$host-$bcc})
    [ -z $HOSTCC ] || CC=$HOSTCC
    local bcxx=${CXX##*/}
    local HOSTCXX=$(command -v ${CXX/%$bcxx/$host-$bcxx})
    [ -z $HOSTCXX ] || CXX=$HOSTCXX
    local bfc=${FC##*/}
    local HOSTFC=$(command -v ${FC/%$bfc/$host-$bfc})
    [ -z $HOSTFC ] || FC=$HOSTFC
}
### Cross compilation support helpers end

parse_early_arguments "$@"

if [ x$quiet = xyes ]; then
    exec &>config.log
else
    exec &> >(tee config.log)
fi

# Create config.status
cat >config.status <<'EOF'
#!/bin/bash
if [ x$1 = x--recheck ]; then _PARSEC_CONFIG_STATUS_OPT_NORECHECK=no;
else _PARSEC_CONFIG_STATUS_OPT_NORECHECK=yes; fi
export _PARSEC_CONFIG_STATUS_OPT_NORECHECK
EOF
tee -a config.status <<EOF
### This program was invoked with the following command line
#
    $0 $(for arg in "$@"; do printf " %q" "$arg"; done)
#
EOF
chmod +x config.status

# Populate arch early on for xcompile platform files
[ x$host != x ] && arch=${host%%-*}

read_platforms "$@"
parse_arguments "$@"

# Populate cmake_executable, do it after the platform file
# in the case it's been changed there.
set_cmake_executable
[ -z "$cmake_executable" ] && echo >&2 "Could not find CMake binary" && exit 3

# Do the host work again after the platform as we may have changed it there
host_adapt


CMAKE_DEFINES+=" ${prefix:+-DCMAKE_INSTALL_PREFIX=$prefix}"
[ x$enable_static = xyes ] && CMAKE_DEFINES+=" -DBUILD_SHARED_LIBS=OFF"
[ x$enable_static = xno ] && CMAKE_DEFINES+=" -DBUILD_SHARED_LIBS=ON"
[ x$enable_shared = xyes ] && CMAKE_DEFINES+=" -DBUILD_SHARED_LIBS=ON"
[ x$enable_shared = xno ] && CMAKE_DEFINES+=" -DBUILD_SHARED_LIBS=OFF"
[ x$enable_shared = xyes ] && [ x$enable_static = xyes ] && echo >&2 "WARNING: due to Cmake limitations, you have to choose exclusively between static and shared build. This build will be static."
[ x$enable_c11 = xyes ] && CMAKE_DEFINES+=" -DSUPPORT_C11=ON"
[ x$enable_c11 = xno ] && CMAKE_DEFINES+=" -DSUPPORT_C11=OFF"
[ x$enable_cxx = xyes ] && CMAKE_DEFINES+=" -DSUPPORT_CXX=ON"
[ x$enable_cxx = xno ] && CMAKE_DEFINES+=" -DSUPPORT_CXX=OFF"
[ x$enable_fortran = xyes ] && CMAKE_DEFINES+=" -DSUPPORT_FORTRAN=ON"
[ x$enable_fortran = xno ] && CMAKE_DEFINES+=" -DSUPPORT_FORTRAN=OFF"
[ x$enable_doc = xyes ] && CMAKE_DEFINES+=" -DBUILD_DOCUMENTATION=ON"
[ x$enable_doc = xno ] && CMAKE_DEFINES+=" -DBUILD_DOCUMENTATION=OFF"
[ x$enable_testing = xyes ] && CMAKE_DEFINES+=" -DBUILD_TESTING=ON"
[ x$enable_testing = xno ] && CMAKE_DEFINES+=" -DBUILD_TESTING=OFF"

if [ -z "$enable_debug" ]; then CMAKE_DEFINES+=" -DCMAKE_BUILD_TYPE=RelWithDebInfo"
elif [[ "$enable_debug" =~ ^no$ ]]; then
    CMAKE_DEFINES+=" -DCMAKE_BUILD_TYPE=Release"
elif [[ $enable_debug =~ ^((yes|paranoid|noisier|history),?)+$ ]]; then
    CMAKE_DEFINES+=" -DCMAKE_BUILD_TYPE=Debug"
    [[ $enable_debug =~ paranoid ]] && CMAKE_DEFINES+=" -DPARSEC_DEBUG_PARANOID=ON"
    [[ $enable_debug =~ noisier ]] && CMAKE_DEFINES+=" -DPARSEC_DEBUG_NOISIER=ON"
    [[ $enable_debug =~ history ]] && CMAKE_DEFINES+=" -DPARSEC_DEBUG_HISTORY=ON"
else echo >&2 "Option $enable_debug is invalid (can be yes|paranoid|noisier|history|no)"; exit 1; fi

[ x$enable_prof_trace = xyes ] && CMAKE_DEFINES+=" -DPARSEC_PROF_TRACE=ON"
[ x$enable_prof_trace = xno ] && CMAKE_DEFINES+=" -DPARSEC_PROF_TRACE=OFF"
[ x$enable_prof_calltrace = xyes ] && CMAKE_DEFINES+=" -DPARSEC_PROF_CALLTRACE=ON"
[ x$enable_prof_calltrace = xno ] && CMAKE_DEFINES+=" -DPARSEC_PROF_CALLTRACE=OFF"
[ x$enable_prof_grapher = xyes ] && CMAKE_DEFINES+=" -DPARSEC_PROF_GRAPHER=ON"
[ x$enable_prof_grapher = xno ] && CMAKE_DEFINES+=" -DPARSEC_PROF_GRAPHER=OFF"
[ x$enable_prof_pins = xyes ] && CMAKE_DEFINES+=" -DPARSEC_PROF_PINS=ON"
[ x$enable_prof_pins = xno ] && CMAKE_DEFINES+=" -DPARSEC_PROF_PINS=OFF"

if [[ x$enable_prof_dryrun =~ ^x((yes|no|body|dep),?)*$ ]]; then
    [[ $enable_prof_dryrun =~ yes ]] && CMAKE_DEFINES+=" -DPARSEC_PROF_DRY_RUN=ON"
    [[ $enable_prof_dryrun =~ dep ]] && CMAKE_DEFINES+=" -DPARSEC_PROF_DRY_DEP=ON"
    [[ $enable_prof_dryrun =~ body ]] && CMAKE_DEFINES+=" -DPARSEC_PROF_DRY_BODY=ON"
    [[ $enable_prof_dryrun =~ no ]] && CMAKE_DEFINES+=" -DPARSEC_PROF_DRY_RUN=OFF -DPARSEC_PROF_DRY_BODY=OFF -DPARSEC_PROF_DRY_DEP=OFF"
fi

case x$with_tau in
xno) CMAKE_DEFINES+=" -DPARSEC_PROF_TAU=OFF";;
xyes) CMAKE_DEFINES+=" -DPARSEC_PROF_TAU=ON";;
x) ;;
*) CMAKE_DEFINES+=" -DPARSEC_PROF_TAU=ON -DTAU_ROOT=$(printf %q "$with_tau")";;
esac

case x$with_papi in
xno) CMAKE_DEFINES+=" -DPARSEC_PROF_TRACE=OFF"
    if [[ x$CMAKE_DEFINES =~ PARSEC_PROF_TRACE=ON ]]; then
        echo >&2 "WARNING: PAPI is disabled but prof-trace had been requested. Traces have been disabled."
        CMAKE_DEFINES="${CMAKE_DEFINES/-DPARSEC_PROF_TRACE=ON/}"
    fi;;
xyes) CMAKE_DEFINES+=" -DPARSEC_PROF_TRACE=ON";;
x) ;;
*) CMAKE_DEFINES+=" -DPAPI_DIR=$(printf %q "$with_papi")";;
esac

case x$with_gtg in
xno) ;; # No CMAKE control to remove if available
xyes) ;; # No CMAKE control to force using
x) ;;
*) CMAKE_DEFINES+=" -DGTG_DIR=$(printf %q "$with_gtg")";;
esac

case x$with_ayudame in
xno) ;; # No CMAKE control to remove if available
xyes) ;; # No CMAKE control to force using
x) ;;
*) CMAKE_DEFINES+=" -DAYUDAME_DIR=$(printf %q "$with_ayudame")";;
esac

case x$with_hwloc in
xno) ;; # No CMAKE control to remove if available
xyes) ;; # No CMAKE control to force using
x) ;;
*) CMAKE_DEFINES+=" -DHWLOC_DIR=$(printf %q "$with_hwloc")";;
esac

case x$with_mpi in
xno) echo >&2 "WARNING: MPI is required to build this version of PaRSEC -- --without-mpi has been ignored.";;
xyes) ;;
x) ;;
*)
    #TODO: deal with icc/spectrum and other variants
    CMAKE_DEFINES+=" -DMPI_C_COMPILER=$(printf %q "$(PATH=$with_mpi:$with_mpi/bin64:$with_mpi/bin command -v mpicc)")"
    CMAKE_DEFINES+=" -DMPI_CXX_COMPILER=$(printf %q "$(PATH=$with_mpi:$with_mpi/bin64:$with_mpi/bin command -v mpicxx)")"
    CMAKE_DEFINES+=" -DMPI_Fortran_COMPILER=$(printf %q "$(PATH=$with_mpi:$with_mpi/bin64:$with_mpi/bin command -v mpif90)")"
esac
[ x$enable_collectives = xyes ] && CMAKE_DEFINES+=" -DPARSEC_DIST_COLLECTIVES=ON"
[ x$enable_collectives = xno ] && CMAKE_DEFINES+=" -DPARSEC_DIST_COLLECTIVES=OFF"


case x$with_cuda in
xno) CMAKE_DEFINES+=" -DPARSEC_GPU_WITH_CUDA=OFF";;
xyes) CMAKE_DEFINES+=" -DPARSEC_GPU_WITH_CUDA=ON";;
x) ;;
*) CMAKE_DEFINES+=" -DPARSEC_GPU_WITH_CUDA=ON -DCUDA_TOOLKIT_ROOT_DIR=$(printf %q "$with_cuda") ${CC:+-DCUDA_HOST_COMPILER=$(printf %q "$(command -v $CC)")} ";;
esac

case x$with_cuda_sm_targets in
xyes) ;;
xno) CMAKE_DEFINES+=" -DCUDA_SM_TARGETS=";;
x) ;;
*) CMAKE_DEFINES+=" -DCUDA_SM_TARGETS='${with_cuda_sm_targets/,/;}'";;
esac


case x$with_python in
xno) echo >&2 "Python is required. Please provide a path to the python executable."; exit 3;;
xyes) ;;
x) ;;
*)  PYTHON_EXECUTABLES=$(PATH="$with_python:$with_python/bin:${PATH}" command -v $with_python python{,3,2})
    for pe in $PYTHON_EXECUTABLES; do
        [[ $pe =~ $with_python ]] && PYTHON_EXECUTABLE=$pe && break
    done
esac

case x$enable_python_venv in
xyes) set_python_venv ;
      pe=$(command -v $PWD/venv/bin/python)
      [[ $pe ]] && PYTHON_EXECUTABLE=$pe;;
*) ;;
esac

[[ x$PYTHON_EXECUTABLE != x ]] && CMAKE_DEFINES+=" -DPython_EXECUTABLE=$(printf %q "$PYTHON_EXECUTABLE")"


case x$with_ninja in
xno) ;;
xyes) cmake_generator="Ninja";; # do as we are told no questions asked.
*) if cmake --help | grep '^\s*Ninja\s*=' -q ; then
    if [ x$with_ninja = x ]; then
        # just probe, if nothing found that's ok.
        NINJA_EXECUTABLES=$(command -v ninja) || true
    else
        NINJA_EXECUTABLES=$(PATH="$with_ninja:$with_ninja/bin:${PATH}" command -v $with_ninja ninja)
    fi
    if [ "$NINJA_EXECUTABLES" ]; then
        cmake_generator="Ninja"
    fi
   fi
esac

# CMAKE INVOCATION

CMAKE_COMMAND="$ENVVARS $cmake_executable -G'$cmake_generator' $srcdir $CMAKE_DEFINES $CMAKE_DEFINES_RAW"

cat <<EOF
### CMake generated invocation
#
    $CMAKE_COMMAND
#
EOF

if [ x$nocreate != xyes ]; then
    [ x$_PARSEC_CONFIG_STATUS_OPT_NORECHECK != xyes ] && echo "Removing Cmake Cache..." && rm -rf CMakeCache.txt CMakeFiles
    eval $CMAKE_COMMAND
    cat<<EOF
#
### CMake Generator: $cmake_generator
#
EOF
fi

