#!/usr/bin/env bash

CONFIG="config.mk"
PREFIX="/usr/local"
VERSION=$(grep "define PNGQUANT_VERSION" ../pngquant.c | grep -Eo "[12]\.[0-9.]+")

DEBUG=
SSE=auto
OPENMP=
EXTRA_CFLAGS=
EXTRA_LDFLAGS=

# make gcc default compiler unless CC is already set
CC=${CC:-gcc}

help() {
    printf "%4s %s\n" "" "$1"
}

for i in "$@"; do
    case $i in
    --help)
        echo
        help "--prefix=                     installation directory [$PREFIX]"
        help "--extra-cflags=               append to CFLAGS"
        help "--extra-ldflags=              append to LDFLAGS"
        echo
        help "--enable-debug"
        help "--enable-sse/--disable-sse    enable/disable SSE instructions"
        echo
        help "--with-openmp                 compile with multicore support"
        echo
        exit 0
        ;;
    # Can be set before or after configure. Latter overrides former.
    CC=*)
        CC=${i#*=}
        ;;
    CFLAGS=*)
        CFLAGS=${i#*=}
        ;;
    LDFLAGS=*)
        LDFLAGS=${i#*=}
        ;;
    --enable-debug)
        DEBUG=1
        ;;
    --enable-sse)
        SSE=1
        ;;
    --disable-sse)
        SSE=0
        ;;
    --with-openmp)
        OPENMP=1
        ;;
    --prefix=*)
        PREFIX=${i#*=}
        ;;
    # can be used multiple times or in quotes to set multiple flags
    --extra-cflags=*)
        EXTRA_CFLAGS="$EXTRA_CFLAGS ${i#*=}"
        ;;
    --extra-ldflags=*)
        EXTRA_LDFLAGS="$EXTRA_LDFLAGS ${i#*=}"
        ;;
    *)
        echo "error: unknown switch ${i%%=*}"
        exit 1
        ;;
    esac
done

# If someone runs sudo make install as very first command, and configure later,
# $CONFIG cannot be overwritten, and must be deleted before continuing.
if [[ -f "$CONFIG" && ! -w "$CONFIG" ]]; then
    echo "Cannot overwrite file $CONFIG! Please delete it."
    exit 1
fi

cflags() {
    CFLAGS="$CFLAGS $1"
}

lflags() {
    LDFLAGS="$LDFLAGS $1"
}

status() {
    printf "%10s: %s\n" "$1" "$2"
}

# Append to CFLAGS if compiler supports flag, with optional prerequisite.
# Fails on errors and warnings.
conditional_cflags() {
    if [ -z "$("$CC" -xc -S -o /dev/null $2 $1 <(echo) 2>&1)" ]; then
        cflags "$1"
    fi
}

error() {
    status "$1" "error ... $2"
    echo
    exit 1
}

echo

# basic check
if ! "$CC" -xc -std=c99 <(echo "int main(){}") -o /dev/null &> /dev/null; then
    error "Compiler" "$CC is no C compiler"
fi

status "Compiler" "$CC"

# init flags
CFLAGS=${CFLAGS:--O3 -fno-math-errno -funroll-loops -fomit-frame-pointer -Wall}
cflags "-std=c99 -I."
lflags "-lm lib/libimagequant.a"

# DEBUG
if [ -z "$DEBUG" ]; then
    cflags "-DNDEBUG"
    status "Debug" "no"
else
    cflags "-g"
    status "Debug" "yes"
fi

# SSE
if [ "$SSE" = 'auto' ]; then
    if [[ "$(uname -m)" =~ (amd|x86_)64 ||
          "$(grep -E -m1 "^flags" /proc/cpuinfo)" =~ "sse" ]]; then
        SSE=1
    fi
fi

if [ "$SSE" -eq 1 ]; then
    status "SSE" "yes"
    cflags "-DUSE_SSE=1"
    cflags "-msse"
    # Silence a later ICC warning due to -msse working slightly different.
    conditional_cflags "-wd10121"
    # Must be set explicitly for GCC on x86_32. Other compilers imply it.
    conditional_cflags "-mfpmath=sse" "-msse"
elif [ "$SSE" -eq 0 ]; then
    status "SSE" "no"
    cflags "-DUSE_SSE=0"
fi

# OpenMP
if [ -n "$OPENMP" ]; then
    if [[ "$("$CC" -xc -E -fopenmp <(echo -e \
          "#ifdef _OPENMP
           #include <omp.h>
           #endif") 2>&1)" =~ "omp_get_thread_num" ]]; then
        cflags "-fopenmp"
        lflags "-fopenmp"
        status "OpenMP" "yes"
    else
        error "OpenMP" "not supported by compiler"
    fi
else
    # silence warnings about omp pragmas
    cflags "-Wno-unknown-pragmas"
    conditional_cflags "-wd3180" # ICC
    status "OpenMP" "no"
fi

echo

# As of GCC 4.5, 387 fp math is significantly slower in C99 mode without this.
# Note: CPUs without SSE2 use 387 for doubles, even when SSE fp math is set.
conditional_cflags "-fexcess-precision=fast"

# Intel C++ Compiler

# ICC does usually only produce fast(er) code when it can optimize to the full
# capabilites of the (Intel) CPU. This is equivalent to -march=native for GCC.
conditional_cflags "-xHOST"

# Disable unsafe fp optimizations and enforce fp precision as set in the source.
conditional_cflags "-fp-model source"

# Silence a gold linker warning about string misalignment.
conditional_cflags "-falign-stack=maintain-16-byte"

lflags "-lm" # Ubuntu requires this library last, issue #38

if [ -n "$EXTRA_CFLAGS" ]; then
    cflags "$EXTRA_CFLAGS"
fi

if [ -n "$EXTRA_LDFLAGS" ]; then
    lflags "$EXTRA_LDFLAGS"
fi

# Overwrite previous configuration.
echo "
# auto-generated by configure
PREFIX = $PREFIX
VERSION = $VERSION
CC = $CC
CFLAGS = $CFLAGS
LDFLAGS = $LDFLAGS
" > $CONFIG