#!/usr/bin/env bash
# Cross-compiler wrapper for build systems (configure, CMake, Meson): host gcc
# with the system's musl, start-up code and linker script.
#
#   CC=/path/to/sdk/koi-gcc CXX=/path/to/sdk/koi-g++ ./configure --host=x86_64-linux-musl
#
# Called as koi-g++ (a link) it compiles C++ with libstdc++.
set -euo pipefail

SDK=$(cd "$(dirname "$(readlink -f "$0")")" && pwd)
LIBC=$SDK/libc
case "$(basename "$0")" in
    *++) DRIVER=${KOI_HOST_CXX:-g++}; CPLUS=1 ;;
    *) DRIVER=${KOI_HOST_CC:-gcc}; CPLUS=0 ;;
esac

LINKING=1
for argument in "$@"; do
    case "$argument" in
        -c|-S|-E|-M|-MM|-fsyntax-only) LINKING=0 ;;
    esac
done
[ $# -eq 0 ] && LINKING=0

INCLUDE=(-nostdinc)
if [ "$CPLUS" = 1 ]; then
    VERSION=$(ls "$LIBC/include/c++" | head -1)
    INCLUDE+=(-nostdinc++ -isystem "$LIBC/include/c++/$VERSION"
              -isystem "$LIBC/include/c++/$VERSION/x86_64-linux-musl")
fi
INCLUDE+=(-isystem "$LIBC/include" -isystem "$($DRIVER -print-file-name=include)")

# Position-independent, no red zone, no stack protector.
FLAGS=(-fpie -mno-red-zone -fno-stack-protector -DKOI_HOSTED -D__KOI_DOS__)

if [ "$LINKING" = 0 ]; then
    exec "$DRIVER" "${FLAGS[@]}" "${INCLUDE[@]}" "$@"
fi

LIBGCC=$LIBC/lib/libgcc.a
[ -f "$LIBGCC" ] || LIBGCC=$($DRIVER -print-libgcc-file-name)
# Unwinding (C++ exceptions): the SDK's, else the host's, else none for C.
EH=$LIBC/lib/libgcc_eh.a
[ -f "$EH" ] || EH=$($DRIVER -print-file-name=libgcc_eh.a)
EH_LIB=()
[ -f "$EH" ] && EH_LIB=("$EH")
# Pull in pthread symbols that Mesa and libstdc++ reference weakly.
PTHREAD=()
for name in pthread_mutexattr_init pthread_mutexattr_settype pthread_mutexattr_destroy \
            pthread_mutex_lock pthread_mutex_unlock pthread_once pthread_key_create \
            pthread_getspecific pthread_setspecific pthread_cond_wait pthread_cond_broadcast \
            pthread_cond_signal pthread_create pthread_join pthread_detach pthread_self; do
    PTHREAD+=(-Wl,-u,"$name")
done
# OSMesa parts SDL needs when linked with -lGL.
for argument in "$@"; do
    case "$argument" in
        -lGL|-lOSMesa)
            for name in OSMesaCreateContextAttribs OSMesaMakeCurrent OSMesaDestroyContext \
                        OSMesaGetProcAddress OSMesaPixelStore glFinish; do
                PTHREAD+=(-Wl,-u,"$name")
            done
            CPLUS_LIBS=1
            ;;
    esac
done
LIBS=()
[ "$CPLUS" = 1 ] || [ "${CPLUS_LIBS:-0}" = 1 ] &&
    LIBS+=("$LIBC/lib/libstdc++.a" "$LIBC/lib/libsupc++.a")
exec "$DRIVER" "${FLAGS[@]}" "${INCLUDE[@]}" \
    -nostdlib -pie -Wl,--no-dynamic-linker -Wl,-T,"$LIBC/lib/program-libc.ld" \
    -Wl,--eh-frame-hdr -Wl,--build-id=sha1 -Wl,-z,max-page-size=0x1000 \
    -Wl,-z,noexecstack "${PTHREAD[@]}" \
    -L"$LIBC/lib" "$LIBC/lib/koi_crt.o" "$@" \
    -L"$LIBC/lib" -Wl,--start-group "${LIBS[@]}" "$LIBC/lib/libc.a" \
    "${EH_LIB[@]}" "$LIBGCC" -Wl,--end-group
