#!/bin/bash

### Read configration file and library ###
OM_DRIVER_CONF_DIR=/opt/local/lib/omnicompiler/etc
. ${OM_DRIVER_CONF_DIR}/xmpf90.conf
. ${OMNI_HOME}/libexec/omni_common_lib.sh
. ${OMNI_HOME}/libexec/xmpf90_lib.sh

### Directory for saving intermediate files ###
PID=$$
TEMP_DIR=/tmp/__omni_tmp__${PID}
DEBUG_TEMP_DIR="__omni_tmp__"

### Default options ###
ENABLE_LINKER=true
ONLY_PP=false
ENABLE_CPP=false
VERBOSE=false
ENABLE_DEBUG=false
OUTPUT_TEMPORAL=false
DRY_RUN=false
STOP_PP=false
STOP_FRONTEND=false
STOP_TRANSLATOR=false
STOP_BACKEND=false
STOP_COMPILE=false
ENABLE_OPENMP=false
ENABLE_OPENACC=false
ENABLE_XACC=false
ENABLE_SCALASCA_ALL=false
ENABLE_SCALASCA=false
ENABLE_TLOG_ALL=false
ENABLE_MAIN_XMP=false

### Set options ###
# e.g.) xmpf90 -I/usr/lib a.f b.F c.f90 d.F90 e.o --tmp --Wlfoo lib.a -omp -DTEST -Jdir -lm -o a.out
#
#  output_file="a.out"              # Output file
#  f_files="a.f b.F c.f90 d.F90"    # All fortran files
#  archive_files="lib.a"            # Archive files
#  obj_files="e.o"                  # Object files
#  module_dirs="-Jdir"              # Module dirs (Actually, the variables are changed in xmpf90_set_parameters)
#  lib_args="-lm"                   # Library files
#  define_opts="-DTEST"             # Define options
#  other_args="-I/usr/lib"          # Options for Preprocessor, Compiler, and Linker
# 
#  Note that "-omp" is extracted by xmpf90_set_parameters, and set "ENABLE_OPENMP".
#
# To deal with space-separator in options, the following variables are defined as an array (#278)
output_file=()
f_files=()
archive_files=()
obj_files=()
module_dirs=()
lib_args=()
define_opts=()
other_args=()

# Additional options defined by command line (e.g. --Wl..)
pp_add_opt=()
frontend_add_opt=()
xcode_translator_add_opt=()
native_add_opt=()
backend_add_opt=()
linker_add_opt=()
module_opt=()
trans_module_opt=()
include_opt=()

xmpf90_set_parameters ${@+"$@"}
omni_f_check_file_exist

### Create temporal directory ###
[ $ENABLE_DEBUG = true ] && TEMP_DIR=$DEBUG_TEMP_DIR
# Note that, if TEMP_DIR exists, the TEMP_DIR is not deleted (KAGEMAI #379)

omni_exec mkdir -p $TEMP_DIR

### Clean temporal directory before exit ###
omni_set_trap

### Preprocessor ###
[ $ONLY_PP = true -a -f "${output_file}" ] && omni_exec rm "${output_file}"
[ $ENABLE_OPENMP = true ] && OMNI_FPP_OPT="$OPENMP_OPT_F $OMNI_FPP_OPT"
[ $ENABLE_XACC = true ]   && OMNI_FPP_OPT="-D_XCALABLEACC $OMNI_FPP_OPT"
for file in "${f_files[@]}"; do
    FILE=("${file}")
    FILE_NAME=`omni_f_norm_file_name "${FILE}"`     # ./hoge/fuga.F -> hoge_2f_fuga_2f_a
    EXT=${file##*.}
    FILE_PP=${TEMP_DIR}/"${FILE_NAME}".${EXT}

    if [ $EXT = "F90" -o $EXT = "F" -o $ENABLE_CPP = true ]; then
        # When ">" or ">>" is used, please use "omni_exec_echo" and "omni_exec_run" instead of "omni_exec".
	omni_exec_echo $OMNI_FPP_CMD "${define_opts[@]}" "${include_opt[@]}" "${pp_add_opt[@]}" $OMNI_FPP_OPT "${other_args[@]}" "${FILE}" ">" "${FILE_PP}"
	[ $DRY_RUN = false ] && omni_exec_run  $OMNI_FPP_CMD "${define_opts[@]}" "${include_opt[@]}" "${pp_add_opt[@]}" $OMNI_FPP_OPT "${other_args[@]}" "${FILE}" > "${FILE_PP}"
        # AIX compiler cannot output file with ".i" suffix. So, ">" is used.

	if [ $ONLY_PP = true ]; then
	    if [ "${output_file}" = "" ]; then
		omni_exec cat "${FILE_PP}"
	    else
		omni_exec_echo cat "${FILE_PP_I}" ">>" "${output_file}"
		omni_exec_run  cat "${FILE_PP_I}" >> "${output_file}"
	    fi
	fi
    fi
done
[ $STOP_PP = true ] && exit 0;
[ $ONLY_PP = true -a $ENABLE_DEBUG = true ] && exit 0;            # xmpf90 -E --debug hoge.c (save $TMP_DIR)
[ $ONLY_PP = true ] && { omni_exec rm -rf $TEMP_DIR; exit 0; }  # xmpf90 -E hoge.c

### Frontend ###
[ $ENABLE_OPENACC = true -o $ENABLE_XACC = true ]   && frontend_add_opt+=("-facc")
[ $ENABLE_OPENMP = true ] && frontend_add_opt+=("-fopenmp")
for file in "${f_files[@]}"; do
    FILE=("${file}")
    FILE_NAME=`omni_f_norm_file_name "${FILE}"`     # ./hoge/fuga.F90 -> hoge_2f_fuga_2f_a
    EXT=${file##*.}

    if [ $EXT = "F90" -o $EXT = "F" -o $ENABLE_CPP = true ]; then
	FILE_PP=${TEMP_DIR}/"${FILE_NAME}".${EXT}
    else
	FILE_PP="${FILE}"
    fi
    FILE_IN_X=${TEMP_DIR}/"${FILE_NAME}"_${EXT}_in.xml

    omni_exec $OMNI_F2X_CMD "${include_opt[@]}" "${module_opt[@]}" "${frontend_add_opt[@]}" $OMNI_F2X_OPT "${FILE_PP}" -o "${FILE_IN_X}"
done
[ $STOP_FRONTEND = true ] && exit 0;

### Translator ###
[ $ENABLE_TLOG_ALL = true ]     && OMNI_FX2X_OPT="$OMNI_FX2X_OPT -tlog-all"
[ $ENABLE_SCALASCA_ALL = true ] && OMNI_FX2X_OPT="$OMNI_FX2X_OPT -scalasca-all"
[ $ENABLE_SCALASCA = true ]     && OMNI_FX2X_OPT="$OMNI_FX2X_OPT -scalasca"
[ $ENABLE_OPENACC = true ]      && OMNI_FX2X_OPT="$OMNI_FX2X_OPT -facc"
[ $ENABLE_XACC = true ]         && OMNI_FX2X_OPT="$OMNI_FX2X_OPT -fxacc"

for file in "${f_files[@]}"; do
    FILE=("${file}")
    FILE_NAME=`omni_f_norm_file_name "${FILE}"`     # ./hoge/fuga.f90 -> hoge_2f_fuga_2f_a
    EXT=${file##*.}
    FILE_IN_X=${TEMP_DIR}/"${FILE_NAME}"_${EXT}_in.xml
    FILE_OUT_X=${TEMP_DIR}/"${FILE_NAME}"_${EXT}_out.xml

    omni_exec $OMNI_FX2X_CMD $OMNI_FX2X_OPT "${xcode_translator_add_opt[@]}" "${module_opt[@]}" "${trans_module_opt[@]}" "${FILE_IN_X}"
    # also create ${TEMP_DIR}/${FILE_NAME}_${EXT}_in.F90
    # Note : The BlueGene/Q 's mpi compiler can compile only *.F90 in XMP process.
    # So that remains .F90 extention after process of the native compilier.
done
[ $STOP_TRANSLATOR = true ] && exit 0;

### Backend ###
if [ $OUTPUT_TEMPORAL = true ]; then
    for file in "${f_files[@]}"; do
	FILE=("${file}")
	FILE_NAME=`omni_f_norm_file_name "${FILE}"`     # ./hoge/fuga.f90 -> hoge_2f_fuga_2f_a
	EXT=${file##*.}
	FILE_F90=${TEMP_DIR}/"${FILE_NAME}"_${EXT}_in.F90
	BASENAME=`basename $FILE .$EXT`

	omni_exec cp "${FILE_F90}" __omni_tmp__"${BASENAME}".${EXT}
	echo output __omni_tmp__"${BASENAME}".${EXT}
    done
fi
[ $STOP_BACKEND = true ] && exit 0;

### Native Compiler ###
[ $ENABLE_OPENMP = true ] && native_add_opt+=("$OPENMP_OPT_F")
for file in "${f_files[@]}"; do
    FILE=("${file}")
    FILE_NAME=`omni_f_norm_file_name "${FILE}"`     # ./hoge/fuga.f90 -> hoge_2f_fuga_2f_a
    EXT=${file##*.}
    FILE_USER_O=`basename "${FILE}" .${EXT}`.o
    FILE_F90=${TEMP_DIR}/"${FILE_NAME}"_${EXT}_in.F90
    FILE_O=${TEMP_DIR}/"${FILE_NAME}"_${EXT}.o

    if [ "$target" != "sxace-nec-superux" ]; then
	[ "${module_dir}" != "" ] && omni_exec mkdir -p "${module_dir}"
	omni_exec $OMNI_MPIFC_CMD "${module_dirs[@]}" "${native_add_opt[@]}" $OMNI_MPIFC_OPT "${other_args[@]}" "${FILE_F90}" -o "${FILE_O}"
    else
	## On SX-ACE, when indicating "${FILE_F90}" by an absolute path, "-to" option is ignored.
	## Moreover "-to" option indicates directory for not only module files but also object files.
	## Therefore after creating object files in a directory indicated by "-to" option, move them to a current directry.
	if [ "${module_dir}" = "" ]; then
	    omni_exec $OMNI_MPIFC_CMD "${include_opt[@]}" "${module_dirs[@]}" "${native_add_opt[@]}" $OMNI_MPIFC_OPT "${other_args[@]}" "${FILE_F90}" -o "${FILE_O}"
	else
            omni_exec mkdir -p "${module_dir}"
	    omni_exec $OMNI_MPIFC_CMD "${include_opt[@]}" "${module_dirs[@]}" "${native_add_opt[@]}" $OMNI_MPIFC_OPT "${other_args[@]}" "${FILE_F90}"
	    omni_exec mv "${module_dir}"/"${FILE_NAME}"_${EXT}_in.o ${FILE_O}
	fi
    fi

    ### GPU Compiler ###
    FILE_CU=${TEMP_DIR}/"${FILE_NAME}"_pp.cu
    FILE_GPUO=${TEMP_DIR}/"${FILE_NAME}".gpu.o
    if [ $ENABLE_OPENACC = true ] && [ -e $FILE_CU ]; then
	omni_exec $OMNI_GPUCC_CMD $OMNI_GPUCC_OPT "${FILE_CU}" -o "${FILE_GPUO}"
	FILE_O_TMP=${TEMP_DIR}/"${FILE_NAME}".cpu.o
	omni_exec mv "${FILE_O}" "${FILE_O_TMP}"
	omni_exec ld -r "${FILE_O_TMP}" "${FILE_GPUO}" -o "${FILE_O}"
	omni_exec rm -f "${FILE_O_TMP}"
    fi

    if [ $ENABLE_LINKER = false -a "${output_file}" != "" ]; then
	omni_exec mv "${FILE_O}" "${output_file}"  # only a single file is created.
    else
	omni_exec cp "${FILE_O}" "${FILE_USER_O}"
    fi
done
[ $STOP_COMPILE = true ] && exit 0;
[ $ENABLE_LINKER = false -a $ENABLE_DEBUG = true ] && exit 0;         # xmpf90 -c --debug hoge.c
[ $ENABLE_LINKER = false ] && { omni_exec rm -rf "${TEMP_DIR}"; exit 0; } # xmpf90 -c hoge.c

### Linker ###
# collect initialize modules
for file in "${f_files[@]}"; do
    FILE=("${file}")
    FILE_NAME=`omni_f_norm_file_name "${FILE}"`     # ./hoge/fuga.f90 -> hoge_2f_fuga_2f_a
    EXT=${file##*.}
    FILE_O=${TEMP_DIR}/"${FILE_NAME}"_${EXT}.o
    obj_files+=("${FILE_O}")
done

OMNI_TRAVERSE_OPT="--F --prefix xmpf --nm ${NM}"
[ "${NM_OPT}" != "" ] && OMNI_TRAVERSE_OPT="${OMNI_TRAVERSE_OPT} --nm_opt ${NM_OPT}"
[ ${TARGET} = "powerpc-hitachi-aix" ] && OMNI_TRAVERSE_OPT="${OMNI_TRAVERSE_OPT} --sr"
TRAVERSE_FILE=${TEMP_DIR}/omni_traverse_${PID}.f90
omni_exec $OMNI_TRAVERSE $OMNI_TRAVERSE_OPT -o $TRAVERSE_FILE "${obj_files[@]}" "${archive_files[@]}"

# link
OMNI_LINKER_OPT="$OMNI_LINKER_OPT -ltlog_mpi"

if [ $ENABLE_OPENACC = true -o 1 = 0 ]; then
    [ 1 = 0 ] && OMNI_LINKER_OPT="$OMNI_LINKER_OPT $OMNI_LINKER_CUDA_OPT"
    [ 1 = 0 ] && OMNI_LINKER_OPT="$OMNI_LINKER_OPT $OMNI_LINKER_OPENCL_OPT"
fi
[ $ENABLE_OPENACC = true ] && OMNI_LINKER_OPT="-lacc $OMNI_LINKER_OPT"
TRAVERSE_FILE_O=${TEMP_DIR}/omni_traverse_${PID}.o
omni_exec $OMNI_MPIFC_CMD $OMNI_MPIFC_OPT -c $TRAVERSE_FILE -o $TRAVERSE_FILE_O 
obj_files+=("$TRAVERSE_FILE_O")

if [ "$target" != "sxace-nec-superux" -a "${output_file}" != "" ]; then
    other_args+=("-o" "${output_file[@]}")
elif [ "$target" = "sxace-nec-superux" -a "${output_file}" != "" ]; then
    output_file=${output_file//\ /\\ }  # replace [space] -> \[space]
    other_args+=("-o" "'${output_file[@]}'")
fi

omni_exec $OMNI_LINKER_CMD "${obj_files[@]}" "${linker_add_opt[@]}" "${other_args[@]}" "${archive_files[@]}" "${lib_args[@]}" $OMNI_LINKER_OPT

### Delete temporal directory ###
[ $ENABLE_DEBUG = false ] && omni_exec rm -rf $TEMP_DIR

exit 0
