#!/bin/bash

# Filter extra cmake arguments
# This has no effect when building Charm++ without cmake
if [[ "$1" = "@CMAKE_C_COMPILER@" ]]; then shift; fi
if [[ "$1" = "@CMAKE_CXX_COMPILER@" ]]; then shift; fi
if [[ "$1" = "@CMAKE_Fortran_COMPILER@" ]]; then shift; fi

[[ -z "$AMPICC" ]] && AMPICC="$(basename "$0")"
CHARMBIN="$(dirname "$0")"
CHARMLIB="$CHARMBIN/../lib"
CHARMINC="$CHARMBIN/../include"
. "$CHARMINC/conv-mach-opt.sh"

[[ -z "$AMPICC_MODE" ]] && AMPICC_MODE='ampi'
VERBOSE=''
STANDALONE=''
GLOBALS=''
GLOBALS_SHARED=''
GLOBALS_FUNCPTR=''
EXPLICIT_COMPILATION=''
BUILD_SHARE=''
PASSTHROUGH_COMPILER_OPTIONS=()

ARGS=()
OBJECT=''

processArgs() {
while [[ $# -ne 0 ]]
do
  arg="$1"
  case "$arg" in
  -showme:command|--showme:command)
     shift
     echo "$CHARMBIN/$AMPICC" "${ARGS[@]}" "$@"
     exit 0
     ;;
  -showme:compile|--showme:compile)
     exit 0
     ;;
  -showme:link|--showme:link)
     exit 0
     ;;
  -showme:incdirs|--showme:incdirs)
     exit 0
     ;;
  -showme:libdirs|--showme:libdirs)
     exit 0
     ;;
  -showme:libs|--showme:libs)
     exit 0
     ;;
  -showme:version|--showme:version)
     echo "AMPI ($AMPICC)"
     exit 0
     ;;
  -showme:help|--showme:help)
     echo "AMPI ($AMPICC)"
     exit 0
     ;;
  -showme:*|--showme:*)
     exit 1
     ;;
  -show*|--show*)
     shift
     echo "$CHARMBIN/$AMPICC" "${ARGS[@]}" "$@"
     exit 0
     ;;
  -v|--version|-print-search-dirs)
     PASSTHROUGH_COMPILER_OPTIONS+=("$arg")
     ;;
  -verbose)
     VERBOSE='true'
     ARGS+=("$arg")
     ;;
  -standalone)
     STANDALONE='true'
     ;;

  -fsglobals)
     GLOBALS='fs'
     GLOBALS_SHARED='1'
     ;;
  -pipglobals)
     GLOBALS='pip'
     GLOBALS_SHARED='1'
     GLOBALS_FUNCPTR='1'
     ;;
  -pieglobals)
     GLOBALS='pie'
     GLOBALS_SHARED='1'
     GLOBALS_FUNCPTR='1'
     ;;

  -c)
     EXPLICIT_COMPILATION='true'
     ARGS+=("$arg")
     ;;
  -shared|-G)
     BUILD_SHARE='true'
     ARGS+=("$arg")
     ;;
  -o)
     shift
     OBJECT="$1"
     ;;
  *)
     ARGS+=("$arg")
     ;;
  esac
  shift
done
}

# shellcheck disable=SC2086
processArgs $AMPI_BUILD_FLAGS "$@"

# If there are no filename arguments specified, just pass through
# compiler options to charmc. Helps with configure scripts that
# parse the output to detect compiler versions, search paths, etc.
if [[ ${#ARGS[@]} -eq 0 && ${#PASSTHROUGH_COMPILER_OPTIONS[@]} -ne 0 ]]; then
  "$CHARMBIN/charmc" "${PASSTHROUGH_COMPILER_OPTIONS[@]}"
  exit $?
fi

ARGS+=("${PASSTHROUGH_COMPILER_OPTIONS[@]}")

runCmd() {
  [[ -n "$VERBOSE" ]] && echo "$AMPICC: Executing" "$@" 1>&2
  "$@"
}

if [[ "$GLOBALS" = 'fs' ]]
then
  if [[ "$CMK_SUPPORTS_FSGLOBALS" != '1' ]]
  then
    echo "Error: Prerequisites for -fsglobals support were not detected."
    exit 1
  fi
elif [[ "$GLOBALS" = 'pip' ]]
then
  if [[ "$CMK_SUPPORTS_PIPGLOBALS" != '1' ]]
  then
    echo "Error: Prerequisites for -pipglobals support were not detected."
    exit 1
  fi
elif [[ "$GLOBALS" = 'pie' ]]
then
  if [[ "$CMK_SUPPORTS_PIEGLOBALS" != '1' ]]
  then
    echo "Error: Prerequisites for -pieglobals support were not detected."
    exit 1
  fi
fi

AMPICC_POST_OPTS=()

[[ -n "$STANDALONE" ]] && ARGS+=(-standalone)

ROMIO=()
if [[ -z "$STANDALONE" ]]
then
  [[ "$CMK_AMPI_WITH_ROMIO" = '1' ]] && ROMIO+=(-pthread)

  [[ "$CMK_SUPPORTS_MEMORY_ISOMALLOC" = '1' ]] && ARGS=(-memory isomalloc "${ARGS[@]}")
  ARGS=(-module CommonLBs "${ARGS[@]}")
fi

if [[ -n "$GLOBALS" ]]
then
  USER_SUFFIX="$CMK_USER_SUFFIX.$CMK_SHARED_SUF"
  SHIM_OPTS=(-seq)
  SHARED_OPTS=()
  if [[ -n "$GLOBALS_SHARED" ]]
  then
    SHARED_OPTS+=(-shared)
    [[ "$CMK_MACOSX" != '1' ]] && SHIM_OPTS+=(-fPIE)
    SHIM_MAIN_OBJS=()
  else
    SHIM_OPTS+=(-fPIE)
    SHIM_MAIN_OBJS=("$CHARMLIB/ampi_funcptr_shim_main.o")
  fi

  if [[ -n "$GLOBALS_FUNCPTR" || "$CMK_WINDOWS" = '1' ]]
  then
    SHIM_OPTS+=(-standalone -DAMPI_USE_FUNCPTR)
    SHIM_OBJS=("$CHARMLIB/ampi_funcptr_shim.o" "${SHIM_MAIN_OBJS[@]}")
    [[ "$AMPICC_MODE" = 'ampif' ]] && SHIM_OBJS+=("$CHARMLIB/ampi_funcptr_shim_fortran.o" "$CHARMLIB/ampi_funcptr_shim_fortran_mod.o")
    LOADER_OBJS=("$CHARMLIB/ampi_funcptr_loader.o" "${ROMIO[@]}")
    ROMIO=()
  else
    SHIM_OBJS=()
    LOADER_OBJS=("$CHARMLIB/ampi_funcptr_loader_stub.o")
    [[ "$AMPICC_MODE" = 'ampif' ]] && LOADER_OBJS+=("$CHARMLIB/ampif.o" "$CHARMLIB/ampimod.o")
  fi
  [[ "$AMPICC_MODE" = 'ampif' ]] && SHIM_OBJS+=("$CHARMLIB/ampi_funcptr_shim_fmpimain.o")

  if [[ -z "$EXPLICIT_COMPILATION" && -z "$BUILD_SHARE" && -z "$STANDALONE" ]] # if linking an AMPI executable
  then
    # link the user program as its own file
    [[ -z "$OBJECT" ]] && USEROBJECT="a.out$USER_SUFFIX" || USEROBJECT="${OBJECT%$CMK_POST_EXE}$USER_SUFFIX"
    SHIM_OPTS+=(-standalone '-Wl,-undefined,dynamic_lookup')
    runCmd "$CHARMBIN/charmc" -language "$AMPICC_MODE" "${ARGS[@]}" "${AMPICC_POST_OPTS[@]}" "${SHIM_OPTS[@]}" "${SHIM_OBJS[@]}" "${SHARED_OPTS[@]}" -o "$USEROBJECT"
    status=$?
    [[ $status -ne 0 ]] && exit $status

    # set up linking the loader against the runtime
    AMPICC_POST_OPTS+=(-clear-input "${LOADER_OBJS[@]}" "$CHARMLIB/ampi_globals_$GLOBALS.o")
    # always link the loader as non-Fortran AMPI
    AMPICC_MODE='ampi'

    if [[ "$GLOBALS" = 'pip' ]]
    then
      # look for PiP-glibc
      [[ -z "$PIP_GLIBC_INSTALL_DIR" ]] && PIP_GLIBC_INSTALL_DIR='/opt/pip'
      pipldquery="$PIP_GLIBC_INSTALL_DIR/lib/ld-*.so"
      set -- $pipldquery
      pipld="$1"
      if [[ "$pipld" = "$pipldquery" ]]
      then
        echo 'Note: PiP-glibc not found. Maximum virtualization count will be limited.'
        echo '      Please set and export $PIP_GLIBC_INSTALL_DIR appropriately.'
      else
        AMPICC_POST_OPTS+=("-Wl,--dynamic-linker=$pipld")
      fi
    fi
  else
    AMPICC_POST_OPTS+=("${SHIM_OPTS[@]}")
    [[ -z "$BUILD_SHARE" ]] && AMPICC_POST_OPTS+=("${SHARED_OPTS[@]}")
  fi
fi

[[ -n "$OBJECT" ]] && AMPICC_POST_OPTS+=(-o "$OBJECT")

runCmd "$CHARMBIN/charmc" -language "$AMPICC_MODE" -default-to-aout "${ARGS[@]}" "${AMPICC_POST_OPTS[@]}" "${ROMIO[@]}"
status=$?

# Copy ampirun, but do not overwrite it if it already exists.
[[ $status -eq 0 && ! -f "ampirun" ]] && cp -f "$CHARMBIN/ampirun" .

exit $status
