#!/bin/bash

### Read configration file and library ###
OM_DRIVER_CONF_DIR=/usr/local/etc
. ${OM_DRIVER_CONF_DIR}/xmpcc.conf
. ${OMNI_HOME}/libexec/omni_common_lib.sh
. ${OMNI_HOME}/libexec/xmpcc_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
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=false
ENABLE_SCALASCA_ALL=false
ENABLE_SCALASCA_SELECTIVE=false
ENABLE_TLOG=false
ENABLE_TLOG_ALL=false
ENABLE_TLOG_SELECTIVE=false
DISABLE_LDG=true
DEFAULT_VECLEN=""

### Set options ###
# e.g.) xmpcc -I/usr/lib a.c b.c c.o --tmp --Wlfoo lib.a -omp -DTEST -lm -o a.out
#  
#  output_file="a.out"              # Output file
#  c_files="a.c b.c"                # C files
#  archive_files="lib.a"            # Archive files
#  obj_files="c.o"                  # Object files
#  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 xmpcc_set_parameters(), and set "ENABLE_OPENMP".
#
# To deal with space-separator in options, the following variables are defined as an array (#278)
output_file=()
c_files=()
archive_files=()
obj_files=()
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=()

xmpcc_set_parameters ${@+"$@"}
omni_c_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
[ $ENABLE_DEBUG = true ] && echo "Create ${TEMP_DIR}/"

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

### Preprocessor ###
[ $ONLY_PP = true -a -f "${output_file}" ] && omni_exec rm "${output_file}"

for c_file in "${c_files[@]}"; do
    C_FILE=("${c_file}")
    FILE_NAME=`omni_c_norm_file_name "${C_FILE}"`     # ./hoge/fuga.c -> hoge_2f_fuga_2f_a
    FILE_PP_C=${TEMP_DIR}/"${FILE_NAME}"_pp.c
    FILE_PP_I=${TEMP_DIR}/"${FILE_NAME}"_pp.i

    omni_exec $OMNI_REPLACE_PRAGMA_CMD $OMNI_REPLACE_PRAGMA_OPT "${C_FILE}" -o "${FILE_PP_C}"

    # When ">" or ">>" is used, please use "omni_exec_echo" and "omni_exec_run" instead of "omni_exec".
    omni_exec_echo $OMNI_CPP_CMD $OMNI_CPP_OPT "${pp_add_opt[@]}" "${define_opts[@]}" "${other_args[@]}" "${FILE_PP_C}" ">" "${FILE_PP_I}"
    [ $DRY_RUN = false ] && omni_exec_run  $OMNI_CPP_CMD $OMNI_CPP_OPT "${pp_add_opt[@]}" "${define_opts[@]}" "${other_args[@]}" "${FILE_PP_C}" > "${FILE_PP_I}"
    # 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_I}"
	else
	    omni_exec_echo cat "${FILE_PP_I}" ">>" "${output_file}"
	    omni_exec_run  cat "${FILE_PP_I}" >> "${output_file}"
	fi
    fi
done
[ $STOP_PP = true ] && exit 0;
[ $ONLY_PP = true -a $ENABLE_DEBUG = true ] && exit 0;          # xmpcc -E --debug hoge.c (save $TEMP_DIR)
[ $ONLY_PP = true ] && { omni_exec rm -rf $TEMP_DIR; exit 0; }  # xmpcc -E hoge.c

### Frontend ###
[ $ENABLE_XACC = true ] && OMNI_C2X_OPT="-facc $OMNI_C2X_OPT"
for c_file in "${c_files[@]}"; do
    C_FILE=("${c_file}")
    FILE_NAME=`omni_c_norm_file_name "${C_FILE}"`     # ./hoge/fuga.c -> hoge_2f_fuga_2f_a
    FILE_PP_I=${TEMP_DIR}/"${FILE_NAME}"_pp.i
    FILE_IN_X=${TEMP_DIR}/"${FILE_NAME}"_in.xml

    omni_exec $OMNI_C2X_CMD $OMNI_C2X_OPT "${frontend_add_opt[@]}" "${FILE_PP_I}" -o "${FILE_IN_X}"
done
[ $STOP_FRONTEND = true ] && exit 0;

### Translator ###
[ $ENABLE_TLOG_ALL           = true ] && OMNI_CX2X_OPT="$OMNI_CX2X_OPT -tlog-all"
[ $ENABLE_TLOG_SELECTIVE     = true ] && OMNI_CX2X_OPT="$OMNI_CX2X_OPT -tlog-selective"
[ $ENABLE_SCALASCA_ALL       = true ] && OMNI_CX2X_OPT="$OMNI_CX2X_OPT -scalasca-all"
[ $ENABLE_SCALASCA_SELECTIVE = true ] && OMNI_CX2X_OPT="$OMNI_CX2X_OPT -scalasca-selective"
[ $ENABLE_XACC = true ]         && OMNI_CX2X_OPT="$OMNI_CX2X_OPT -facc"
if [ $ENABLE_XACC = true ]; then
    [ $DISABLE_LDG = true ] && OMNI_CX2X_OPT="$OMNI_CX2X_OPT -no-ldg"
    [ "$DEFAULT_VECLEN" != "" ] && OMNI_CX2X_OPT="$OMNI_CX2X_OPT -default-veclen=${DEFAULT_VECLEN}"
    OMNI_CX2X_OPT="$OMNI_CX2X_OPT -platform=$OPENACC_PLATFORM"
    OMNI_CX2X_OPT="$OMNI_CX2X_OPT -device=$OPENACC_DEVICE"
fi
for c_file in "${c_files[@]}"; do
    C_FILE=("${c_file}")
    FILE_NAME=`omni_c_norm_file_name "${C_FILE}"`     # ./hoge/fuga.c -> hoge_2f_fuga_2f_a
    FILE_IN_X=${TEMP_DIR}/"${FILE_NAME}"_in.xml
    FILE_OUT_X=${TEMP_DIR}/"${FILE_NAME}"_out.xml

    omni_exec $OMNI_CX2X_CMD $OMNI_CX2X_OPT "${xcode_translator_add_opt[@]}" "${FILE_IN_X}" -o "${FILE_OUT_X}"
    # also create ${TEMP_DIR}/${FILE_NAME}_in.c
    omni_exec cp ${TEMP_DIR}/"${FILE_NAME}"_in.c ${TEMP_DIR}/"${FILE_NAME}".c
done
[ $STOP_TRANSLATOR = true ] && exit 0;

### Backend ###
if [ $OUTPUT_TEMPORAL = true ]; then
    for c_file in "${c_files[@]}"; do
	C_FILE=("${c_file}")
	FILE_NAME=`omni_c_norm_file_name "${C_FILE}"`     # ./hoge/fuga.c -> hoge_2f_fuga_2f_a
	FILE_C=${TEMP_DIR}/"${FILE_NAME}".c
	BASENAME=`basename $C_FILE`
    
        omni_exec cp "${FILE_C}" __omni_tmp__"${BASENAME}"
        echo output __omni_tmp__"${BASENAME}"
    done
fi
[ $STOP_BACKEND = true ] && exit 0;

### Native Compiler ###
[ $ENABLE_OPENMP = true ] && OMNI_MPICC_OPT="$OPENMP_OPT_C $OMNI_MPICC_OPT"
[ $ENABLE_SCALASCA = true ] && OMNI_MPICC_CMD="scalasca -instrument -user $OMNI_MPICC_CMD"
for c_file in "${c_files[@]}"; do
    C_FILE=("${c_file}")
    FILE_NAME=`omni_c_norm_file_name "${C_FILE}"`     # ./hoge/fuga.c -> hoge_2f_fuga_2f_a
    FILE_C=${TEMP_DIR}/"${FILE_NAME}".c
    FILE_O=${TEMP_DIR}/"${FILE_NAME}".o
    FILE_USER_O=`basename "${C_FILE}" .c`.o

    omni_exec $OMNI_MPICC_CMD $OMNI_MPICC_OPT "${native_add_opt[@]}" "${other_args[@]}" "${FILE_C}" -o "${FILE_O}"

    ### GPU Compiler ###
    FILE_CU=${TEMP_DIR}/"${FILE_NAME}"_pp.cu
    FILE_GPUO=${TEMP_DIR}/"${FILE_NAME}".gpu.o
    # if [ $ENABLE_XACC = 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_XACC = true ]; then
	if [ $OPENACC_PLATFORM = "CUDA" ]; then
	    FILE_CU=${TEMP_DIR}/"${FILE_NAME}"_pp.cu
	    FILE_GPUO=${TEMP_DIR}/"${FILE_NAME}".gpu.o
	    if [ -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
	elif [ $OPENACC_PLATFORM = "OpenCL" ]; then
	    FILE_CL=${TEMP_DIR}/"${FILE_NAME}"_pp.cl
	    FILE_USER_CL=`basename "${C_FILE}" .c`_pp.cl
	    if [ -e "${FILE_CL}" ]; then
		omni_exec cp "${FILE_CL}" "${FILE_USER_CL}"
	    fi
	fi
    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;         # xmpcc -c --debug hoge.c
[ $ENABLE_LINKER = false ] && { omni_exec rm -rf $TEMP_DIR; exit 0; } # xmpcc -c hoge.c

### Linker ###
# collect initialize modules
for c_file in "${c_files[@]}"; do
    C_FILE=("${c_file}")
    FILE_NAME=`omni_c_norm_file_name "${C_FILE}"`     # ./hoge/fuga.c -> hoge_2f_fuga_2f_a
    FILE_O=${TEMP_DIR}/"${FILE_NAME}".o
    obj_files+=("${FILE_O}")
done
TRAVERSE_FILE_C=${TEMP_DIR}/omni_traverse_${PID}.c
TRAVERSE_FILE_O=${TEMP_DIR}/omni_traverse_${PID}.o
OMNI_TRAVERSE_OPT="--C --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"
[ $ENABLE_XACC = true ] && OMNI_TRAVERSE_XACC_OPT="${OMNI_TRAVERSE_OPT} --prefix acc"
OMNI_TRAVERSE_OPT="${OMNI_TRAVERSE_OPT} --prefix xmpc"
omni_exec $OMNI_TRAVERSE $OMNI_TRAVERSE_OPT -o $TRAVERSE_FILE_C "${obj_files[@]}" "${archive_files[@]}"

omni_exec $OMNI_MPICC_CMD -c $TRAVERSE_FILE_C -o $TRAVERSE_FILE_O

# omni_traverse for XACC
if [ $ENABLE_XACC = true ]; then
    TRAVERSE_FILE_XACC_C=${TEMP_DIR}/omni_traverse_xacc_${PID}.c
    TRAVERSE_FILE_XACC_O=${TEMP_DIR}/omni_traverse_xacc_${PID}.o
    omni_exec $OMNI_TRAVERSE $OMNI_TRAVERSE_XACC_OPT -o $TRAVERSE_FILE_XACC_C "${obj_files[@]}" "${archive_files[@]}"
    omni_exec $OMNI_MPICC_CMD -c $TRAVERSE_FILE_XACC_C -o $TRAVERSE_FILE_XACC_O
fi

# link
[ $ENABLE_SCALASCA = true ] && OMNI_LINKER_CMD="scalasca -instrument -user $OMNI_LINKER_CMD"
[ $ENABLE_TLOG     = true ] && OMNI_LINKER_OPT="$OMNI_LINKER_OPT -ltlog_mpi"

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

obj_files+=("$TRAVERSE_FILE_O")
if [ $ENABLE_XACC = true ]; then
    #OMNI_LINKER_OPT="$OMNI_LINKER_OPT $OMNI_GPUCC_LIB"
    if [ $OPENACC_PLATFORM = "CUDA" ]; then
	OMNI_LINKER_OPT="$OMNI_LINKER_OPT $OMNI_CUDA_LIB"
    elif [ $OPENACC_PLATFORM = "OpenCL" ]; then
	OMNI_LINKER_OPT="$OMNI_LINKER_OPT $OMNI_OPENCL_LIB"
    fi
    obj_files+=("$TRAVERSE_FILE_XACC_O")
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
