#!/bin/bash

### Read configration file and library ###
OM_DRIVER_CONF_DIR=/opt/local/lib/omnicompiler/etc
. ${OM_DRIVER_CONF_DIR}/ompcc.conf
. ${OMNI_HOME}/libexec/omni_common_lib.sh
. ${OMNI_HOME}/libexec/ompcc_lib.sh
. ${OMNI_HOME}/libexec/omni_acc_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
DISABLE_LDG=false
DEFAULT_VECLEN=""

### Set options ###
# e.g.) ompcc -I/usr/lib a.c b.c c.o --tmp --Wlfoo lib.a -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
#
# 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=()

ompcc_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

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

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

if [ "$ENABLE_ACC" = true ]; then
    OMNI_CPP_OPT="$OMNI_CPP_OPT ${OPENACC_DEF}"
else
    OMNI_CPP_OPT="$OMNI_CPP_OPT ${OPENMP_DEF}"
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_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 "${define_opts[@]}" $OMNI_CPP_OPT "${pp_add_opt[@]}" "${other_args[@]}" "${FILE_PP_C}" ">" "${FILE_PP_I}"
    [ "$DRY_RUN" = false ] && omni_exec_run $OMNI_CPP_CMD "${define_opts[@]}" $OMNI_CPP_OPT "${pp_add_opt[@]}" "${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;          # ompcc -E --debug hoge.c (save $TMP_DIR)
[ "$ONLY_PP" = true ] && { omni_exec rm -rf $TEMP_DIR; exit 0; }  # ompcc -E hoge.c

### Frontend ###
[ "$ENABLE_ACC" = 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 ###
if [ "$ENABLE_ACC" = true ]; then
    OMNI_CX2X_OPT="$OMNI_CX2X_OPT -facc"
    [ "$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"
else
    OMNI_CX2X_OPT="$OMNI_CX2X_OPT -fopenmp"
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}"
    # 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 ###
if [ "$ENABLE_ACC" = true ]; then
    OMNI_CC_OPT="$OMNI_CC_OPT ${OPENACC_DEF}"
else
    OMNI_CC_OPT="$OMNI_CC_OPT ${OPENMP_DEF}"
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_C=${TEMP_DIR}/"${FILE_NAME}".c
    FILE_O=${TEMP_DIR}/"${FILE_NAME}".o
    FILE_USER_O=`basename "${C_FILE}" .c`.o

    omni_exec $OMNI_CC_CMD $OMNI_CC_OPT "${native_add_opt[@]}" "${other_args[@]}" "${FILE_C}" -o "${FILE_O}"

    ### GPU Compiler ###
    if [ "$OPENACC_PLATFORM" = "CUDA" ]; then
	FILE_CU=${TEMP_DIR}/"${FILE_NAME}"_pp.cu
	if [ -e "${FILE_CU}" ]; then
	    GPUCC_ADD_ARGS=(`omni_acc_cuda_get_args ${other_args[@]}`)
	    GPUCC_ADD_ARGS+=("-arch=sm_`omni_acc_cuda_get_cc_version ${OPENACC_DEVICE}`")
	    omni_acc_cuda_compile ${FILE_CU} ${FILE_O} ${GPUCC_ADD_ARGS[@]}
	fi
    elif [ "$OPENACC_PLATFORM" = "OpenCL" ]; then
	FILE_CL=${TEMP_DIR}/"${FILE_NAME}"_pp.cl
	if [ -e "${FILE_CL}" ]; then
	    FILE_USER_CL="${FILE_NAME}"_pp.cl
	    omni_exec cp "${FILE_CL}" "${FILE_USER_CL}"
	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;         # ompcc -c --debug hoge.c
[ "$ENABLE_LINKER" = false ] && { omni_exec rm -rf $TEMP_DIR; exit 0; } # ompcc -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
if [ "$ENABLE_ACC" = true ]; then
    OMNI_TRAVERSE_OPT="--C --nm ${NM} --prefix acc"
    [ "${TARGET}" = "powerpc-hitachi-aix" ] && OMNI_TRAVERSE_OPT="${OMNI_TRAVERSE_OPT} --sr"
    TRAVERSE_FILE_C=${TEMP_DIR}/omni_traverse_${PID}.c
    TRAVERSE_FILE_O=${TEMP_DIR}/omni_traverse_${PID}.o
    omni_exec $OMNI_TRAVERSE $OMNI_TRAVERSE_OPT -o $TRAVERSE_FILE_C "${obj_files[@]}" "${archive_files[@]}"
    omni_exec $OMNI_CC_CMD -c $TRAVERSE_FILE_C -o $TRAVERSE_FILE_O
fi

# link
if [ "$ENABLE_ACC" = true ]; then
    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_O")
else
    OMNI_LINKER_OPT="$OMNI_LINKER_OPT -lompc_mutex_pthread -lpthread -ltlog"
    obj_files+=("$OMPC_MAIN_O")
fi

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
