#! /bin/sh
# Simple configure script for c-lightning.

set -e

CONFIGURATOR=ccan/tools/configurator/configurator
CONFIG_VAR_FILE=config.vars
CONFIG_HEADER=ccan/config.h
BASE_WARNFLAGS="-Wall -Wundef -Wmissing-prototypes -Wmissing-declarations -Wstrict-prototypes -Wold-style-definition -Werror"

usage_with_default()
{
    if [ $# = 4 ]; then
	if [ "$2" = 1 ]; then
	    DEF=$3
	else
	    DEF=$4
	fi
    else
	DEF=$2
    fi
    echo "  $1 (default $DEF)"
}

# Given DEVELOPER, what COPTFLAGS do we default to.
default_coptflags()
{
    if [ "$1" = 0 ]; then
	echo "-Og"
    fi
}

# Given COPTFLAGS, HAVE_GCC and HAVE_MODERN_GCC, what CWARNFLAGS to default to?
default_cwarnflags()
{
    F=$BASE_WARNFLAGS
    # Clang doesn't like -Wno-error=maybe-uninitialized, but doesn't seem
    # to give spurious warnings, either.
    if [ "$2" = 1 ]; then
	# With old gccs, or optimization != -O3, we need to suppress some warnings.
	if [ -n "${1##*-O3*}" ] || [ "$3" != "1" ]; then
	    F="$F -Wno-error=maybe-uninitialized"
	fi
    fi
    echo "$F"
}

default_pytest()
{
    PYTEST_BINS="pytest-3 pytest3 pytest py.test"
    for p in $PYTEST_BINS; do
	if [ "$(which $p)" != "" ] ; then
	    "$p" --version 2>&1 | grep -q "python3" || continue
	    echo "$p"
	    return
	fi
    done

    PYTHON_BINS="python python3"
    for p in $PYTHON_BINS; do
        if [ "$(which $p)" != "" ] ; then
            $p --version 2>&1 | grep -q "Python 3." || continue
            if $p -c "import pytest" 2>/dev/null ; then
                echo "$p -m pytest"
                return
            fi
        fi
    done
}

default_valgrind_setting()
{
    # Valgrind must accept all these options (might exit with error 7 though
    # if /bin/true leaks mem on your system!)
    if valgrind -q --error-exitcode=7 --track-origins=yes --leak-check=full --show-reachable=yes --errors-for-leak-kinds=all /bin/true >/dev/null 2>&1 || [ $? = 7 ]; then
	echo 1
    else
	echo 0
    fi
}

set_defaults()
{
    # Default values, loaded from environment or canned.
    # Note that ":-" means substitute if empty or unset, "-" means only if unset
    # which matters since you might explicitly set of these blank.
    PREFIX=${PREFIX:-/usr/local}
    CC=${CC:-cc}
    CDEBUGFLAGS=${CDEBUGFLAGS--std=gnu11 -g -fstack-protector}
    DEVELOPER=${DEVELOPER:-0}
    EXPERIMENTAL_FEATURES=${EXPERIMENTAL_FEATURES:-0}
    COMPAT=${COMPAT:-1}
    STATIC=${STATIC:-0}
    ASAN=${ASAN:-0}
    PYTEST=${PYTEST-$(default_pytest)}
    COPTFLAGS=${COPTFLAGS-$(default_coptflags "$DEVELOPER")}
    CONFIGURATOR_CC=${CONFIGURATOR_CC-$CC}
    VALGRIND=${VALGRIND:-$(default_valgrind_setting)}
}

usage()
{
    echo "Usage: ./configure [--reconfigure] [setting=value] [options]"
    echo "If --reconfigure is specified, $CONFIG_VAR_FILE will set defaults."
    echo "Default settings:"
    set_defaults
    DEFAULT_COPTFLAGS="$(default_coptflags $DEVELOPER)"
    # We assume we have a modern gcc.
    DEFAULT_CWARNFLAGS="$(default_cwarnflags ""$DEFAULT_COPTFLAGS"" 1 1)"
    usage_with_default "CC" "$CC"
    usage_with_default "CWARNFLAGS" "$DEFAULT_CWARNFLAGS"
    usage_with_default "COPTFLAGS" "$DEFAULT_COPTFLAGS"
    usage_with_default "CDEBUGFLAGS" "$CDEBUGFLAGS"
    usage_with_default "CONFIGURATOR_CC" "${CONFIGURATOR_CC:-$CC}"
    echo "    To override compile line for configurator itself"
    usage_with_default "PYTEST" "$PYTEST"
    usage_with_default "VALGRIND" "$VALGRIND"

    echo "Options include:"
    usage_with_default "--prefix=" "$PREFIX"
    echo "    Prefix for make install"
    usage_with_default "--enable/disable-developer" "$DEVELOPER" "enable" "disable"
    echo "    Developer mode, good for testing"
    usage_with_default "--enable/disable-experimental-features" "$EXPERIMENTAL_FEATURES" "enable" "disable"
    echo "    Developer mode, good for testing"
    usage_with_default "--enable/disable-compat" "$COMPAT" "enable" "disable"
    echo "    Compatibility mode, good to disable to see if your software breaks"
    usage_with_default "--enable/disable-valgrind" "(autodetect)"
    echo "    Valgrind binary to use for tests"
    usage_with_default "--enable/disable-static" "$STATIC" "enable" "disable"
    echo "    Static link binary"
    usage_with_default "--enable/disable-address-sanitizer" "$ASAN" "enable" "disable"
    echo "    Compile with address-sanitizer"
    exit 1
}

add_var()
{
    if [ -n "$2" ]; then
        echo "Setting $1... $2"
    else
        echo "$1 not found"
    fi
    echo "$1=$2" >> $CONFIG_VAR_FILE
    [ -z "$3" ] || echo "#define $1 $2" >> "$3"
}

for opt in "$@"; do
    case "$opt" in
	--reconfigure)
	    # Figure out what defaulT COPTFLAGS was for this config.vars
	    DEFAULT_COPTFLAGS=
	    # Set from values if not already set.
	    while IFS='=' read VAR VAL; do
		if eval [ -z \${$VAR+x} ]; then eval $VAR=\"$VAL\"; fi
		if [ "$VAR" = DEVELOPER ]; then
		   DEFAULT_COPTFLAGS=$(default_coptflags "$VAL")
		fi
	    done < $CONFIG_VAR_FILE
	    # If we were those defaults, unset so we get new defaults in
	    # case DEVELOPER has changed.
	    if [ x"$COPTFLAGS" = x"$DEFAULT_COPTFLAGS" ]; then
		unset COPTFLAGS
	    fi
	    ;;
	CC=*) CC="${opt#CC=}";;
	CONFIGURATOR_CC=*) CONFIGURATOR_CC="${opt#CONFIGURATOR_CC=}";;
	CWARNFLAGS=*) CWARNFLAGS="${opt#CWARNFLAGS=}";;
	CDEBUGFLAGS=*) CDEBUGFLAGS="${opt#CDEBUGFLAGS=}";;
	COPTFLAGS=*) COPTFLAGS="${opt#COPTFLAGS=}";;
	PYTEST=*) PYTEST="${opt#PYTEST=}";;
	--prefix=*) PREFIX="${opt#--prefix=}";;
	--enable-developer) DEVELOPER=1;;
	--disable-developer) DEVELOPER=0;;
	--enable-experimental-features) EXPERIMENTAL_FEATURES=1;;
	--disable-experimental-features) EXPERIMENTAL_FEATURES=0;;
	--enable-compat) COMPAT=1;;
	--disable-compat) COMPAT=0;;
	--enable-valgrind) VALGRIND=1;;
	--disable-valgrind) VALGRIND=0;;
	--enable-static) STATIC=1;;
	--disable-static) STATIC=0;;
	--enable-address-sanitizer) ASAN=1;;
	--disable-address-sanitizer) ASAN=0;;
	--help|-h) usage;;
	*)
	    echo "Unknown option '$opt'" >&2
	    usage
	    ;;
    esac
done

# Now fill in any unset vars.
set_defaults

# We assume warning flags don't affect congfigurator that much!
echo -n "Compiling $CONFIGURATOR..."
$CC ${CWARNFLAGS-$BASE_WARNFLAGS} $CDEBUGFLAGS $COPTFLAGS -o $CONFIGURATOR $CONFIGURATOR.c
echo "done"

if [ "$ASAN" = "1" ]; then
    if [ "$CC" = "clang" ]; then
	echo "Address sanitizer (ASAN) is currently only supported with gcc"
	exit 1
    fi
    if [ "$VALGRIND" = "1" ]; then
	echo "Address sanitizer (ASAN) and valgrind cannot be enabled at the same time"
	exit 1
    fi
fi

rm -f $CONFIG_VAR_FILE.$$
$CONFIGURATOR --extra-tests --autotools-style --var-file=$CONFIG_VAR_FILE.$$ --header-file=$CONFIG_HEADER --configurator-cc="$CONFIGURATOR_CC" "$CC" ${CWARNFLAGS-$BASE_WARNFLAGS} $CDEBUGFLAGS $COPTFLAGS <<EOF
var=HAVE_GOOD_LIBSODIUM
desc=libsodium with IETF chacha20 variants
style=DEFINES_EVERYTHING|EXECUTE|MAY_NOT_COMPILE
link=-lsodium
code=
#include <sodium.h>
#include <stdio.h>

int main(void)
{
	printf("%p\n", crypto_aead_chacha20poly1305_ietf_encrypt);
	printf("%d\n", crypto_aead_chacha20poly1305_ietf_NPUBBYTES);
	return 0;
}
/*END*/
var=HAVE_SQLITE3_EXPANDED_SQL
desc=sqlite3_expanded_sql
style=DEFINES_EVERYTHING|EXECUTE|MAY_NOT_COMPILE
link=-lsqlite3
code=
#include <sqlite3.h>
#include <stdio.h>

int main(void)
{
	printf("%p\n", sqlite3_expanded_sql);
	return 0;
}
/*END*/
var=HAVE_GCC
desc=compiler is GCC
style=OUTSIDE_MAIN
code=
#ifndef __GNUC__
#error "Not GCC"
#endif
#ifdef __clang__
#error "clang"
#endif
/*END*/
var=HAVE_MODERN_GCC
desc=GCC version is 7 or above
style=OUTSIDE_MAIN
code=
#if __GNUC__ < 7
#error "Not modern GCC"
#endif
/*END*/
EOF
mv $CONFIG_VAR_FILE.$$ $CONFIG_VAR_FILE

# Now we can finally set our warning flags
if [ -z ${CWARNFLAGS+x} ]; then
    CWARNFLAGS=$(default_cwarnflags "$COPTFLAGS" \
		    $(sed -n 's/^HAVE_GCC=//p' < $CONFIG_VAR_FILE) \
		    $(sed -n 's/^HAVE_MODERN_GCC=//p' < $CONFIG_VAR_FILE) )
fi

add_var PREFIX "$PREFIX"
add_var CC "$CC"
add_var CONFIGURATOR_CC "$CONFIGURATOR_CC"
add_var CWARNFLAGS "$CWARNFLAGS"
add_var CDEBUGFLAGS "$CDEBUGFLAGS"
add_var COPTFLAGS "$COPTFLAGS"
add_var VALGRIND "$VALGRIND"
add_var DEVELOPER "$DEVELOPER" $CONFIG_HEADER
add_var EXPERIMENTAL_FEATURES "$EXPERIMENTAL_FEATURES" $CONFIG_HEADER
add_var COMPAT "$COMPAT" $CONFIG_HEADER
add_var PYTEST "$PYTEST"
add_var STATIC "$STATIC"
add_var ASAN "$ASAN"

# Hack to avoid sha256 name clash with libwally: will be fixed when that
# becomes a standalone shared lib.
echo '#include "ccan_compat.h"' >> $CONFIG_HEADER