#!/bin/sh
#
# Copyright (c) 2020-now by the Zeek Project. See LICENSE for details.

usage() {
    cat << EOF
$(basename "$0") [options] <input files>

    -d          Build a debug version.
    -g          Disable HILTI-side optimizations of the generated code.
    -o <file>   Destination name for the compiled executable; default is "a.out".
    -t          Do not delete tmp files (useful for inspecting, and use with debugger)
    -v          Verbose output, display command lines executing.
    -S          Do not compile the "spicy-driver" host application into executable.

Input files may be anything that spicyc can compile to C++.

EOF
}

mktmp() {
    base=$(basename "$1")
    ext=$2
    cnt=0
    while : ; do
        tmp=${dest}/${base}.${cnt}.tmp.${ext}
        test -e "${tmp}" || break
        cnt=$((cnt + 1))
    done
    touch "${tmp}"
    echo "${tmp}"
}

mkcc() {
    tmp=$(mktmp "$1" cc)
    echo "${tmp}"
}

execute() {
    # Remove absolute path of executable
    test "${verbose}" = 1 && echo "$@" | sed 's#^[^ ]*/\([a-zA-Z+_-]\{1,\}\) #> \1 #'
    $@
}

cleanup() {
   test "${delete_tmps}" = 1 && rm -rf "${dest}"
}

### Main

hiltic_flags=""
spicy_config_flags=""
verbose=0
delete_tmps=1
compile_spicy_driver=1
out=a.out

while getopts "ghdo:Stv" opt; do
    case "$opt" in
        d)
           hiltic_flags="${hiltic_flags} -d"
           spicy_config_flags="--debug"
           ;;

        g)
           hiltic_flags="${hiltic_flags} -g"
           ;;

        o) out=$OPTARG;;
        S) compile_spicy_driver=0;;
        t) delete_tmps=0;;
        v) verbose=1;;

        h) usage; exit 0;;
        *) usage; exit 1;;
    esac
done

shift $((OPTIND - 1))

inputs=$*
test -z "${inputs}" && usage && exit 1
test -z "${out}" && usage && exit 1

base=$(cd "$(dirname "$0")/.." && pwd)

if [ "${out}" != "${out#/}" ]; then
    # absolute path
    dest=${out}.$$.tmp.d
else
    # relative path
    dest=$(pwd)/${out}.$$.tmp.d
fi

rm -rf "${dest}"
mkdir -p "${dest}"

trap cleanup EXIT

for i in $(which hilti-config 2>/dev/null) ${base}/bin/hilti-config ${base}/build/bin/hilti-config; do
   test -x "$i" && hilti_config=$i && break
done

for i in $(which spicy-config 2>/dev/null) ${base}/bin/spicy-config ${base}/build/bin/spicy-config; do
   test -x "$i" && spicy_config=$i && break
done

if [ -z "${hilti_config}" ]; then
    echo cannot find hilti-config
    exit 1
fi

if [ -z "${spicy_config}" ]; then
    echo cannot find spicy-config
    exit 1
fi

cxx="$(${spicy_config} --cxx ${spicy_config_flags}) $(${spicy_config} --cxxflags ${spicy_config_flags})"
ldflags="$(${spicy_config} --ldflags ${spicy_config_flags})"
spicy_lib_dir=$(for i in $(${spicy_config} --libdirs); do test -e "${i}/spicy_rt.hlt" && echo "${i}" && break; done) # extract the directory we want
spicy_driver=${spicy_lib_dir}/spicy-driver-host.cc

rt_modules=""

cc_inputs=""
if [ "${compile_spicy_driver}" = 1 ]; then
    rt_modules="${spicy_lib_dir}/filter.spicy"
    cc_inputs="${cc_inputs} ${spicy_driver}"
fi

spicy_inputs=""
for i in ${inputs}; do
    case "${i}" in
        *.cc)
            cc_inputs="${cc_inputs} ${i}"
            ;;
        *)
            spicy_inputs="${spicy_inputs} ${i}"
            ;;
    esac
done


# Generate C++ output files. We pass `cc_inputs` here as well even though its
# only effect is to cause emitting of generated files.
execute "$("${spicy_config}" --spicyc)" "${hiltic_flags}" -x "${dest}/" "${spicy_inputs}" "${cc_inputs}" "${rt_modules}" || exit 1

cxxs="${cc_inputs} $(find "${dest}" -type f)"

# Compile all C++ code into executable
execute "${cxx}" "${cxxs}" "${ldflags}" -o "${out}" || exit 1
