#! /bin/sh

# configuration script for Apron
#
# generates automatically a suitable Makefile.config


##############################################
# help
#######

help()
{
    cat <<EOF
usage: configure [options]

where options include:
  -prefix dir          installation directory
  -gmp-prefix dir      where to find the GMP library
  -mpfr-prefix dir     where to find the MPFR library
  -ppl-prefix dir      where to find the PPL library
  -java-prefix dir     where to find Java
  -no-cxx              disable C++ support
  -no-ocaml            disable OCaml support
  -no-ocamlfind        disable OCamlfind support
  -no-ocaml-plugins    disable OCaml native plugins
  -no-ppl              disable PPL support
  -no-java             disable Java support
  -absolute-dylibs     force absolute library names (OSX only)

Environment variables that affect configuration:
  CC                   C compiler to use (default: gcc)
  CXX                  C++ compiler to use (default: g++)
  CFLAGS               extra flags to pass to the C compiler
  CXXFLAGS             extra flags to pass to the C++ compiler
  CPPFLAGS             extra flags to pass to the C/C++ preprocessor
  LDFLAGS              extra link flags
  GMP_PREFIX           where to find the GMP library
  MPFR_PREFIX          where to find the MPFR library
  PPL_PREFIX           where to find tye PPL library
  JAVA_HOME            where to find Java

EOF
    exit
}


##############################################
# parse arguments
#################

apron_prefix=/usr/local
has_cxx=1
has_ppl=1
has_ocaml=1
has_ocamlfind=1
has_ocaml_plugins=1
has_java=1
force_absolute_dylib_install_names=0;
ext_dll=so
while : ; do
    case "$1" in
        "") 
            break;;
        -prefix|--prefix)
            apron_prefix="$2"
            shift;;
        -gmp-prefix|--gmp-prefix)
            gmp_prefix="$2"
            shift;;
        -mpfr-prefix|--mpfr-prefix)
            mpfr_prefix="$2"
            shift;;
        -ppl-prefix|--ppl-prefix)
            ppl_prefix="$2"
            shift;;
        -java-prefix|--java-prefix)
            java_prefix="$2"
            shift;;
	-ext-dll|--ext-dll)
	    ext_dll="$2"
	    shift;;
        -no-cxx|--no-cxx)
            has_cxx=0
            has_ppl=0;;
        -no-ppl|--no-ppl)
            has_ppl=0;;
        -no-ocaml|--no-ocaml)
            has_ocaml=0;;
        -no-ocamlfind|--no-ocamlfind)
            has_ocamlfind=0;;
        -no-ocaml-plugins|--no-ocaml-plugins)
            has_ocaml_plugins=0;;
        -no-java|--no-java)
            has_java=0;;
	-absolute-dylibs|--absolute-dylibs)
	    force_absolute_dylib_install_names=1;;
        -help|--help)
            help;;
        *)
            echo "unknown option $1, try -help"
            exit 2;;
    esac
    shift
done


##############################################
# utilities
###########

# print utility
echo_n()
{
    echo "$1" | tr -d '\012'
}


# checkcc cc opt
# checks that compiler cc can compile a simple program with option opt
# if so, add it to acc
checkcomp()
{
    testcc="$1"
    testopt="$2";
    echo_n "checking compilation with $testcc $testopt: "
    rm -f tmp.c tmp.out
    echo "int main() { return 1; }" >> tmp.c
    r=1
    $testcc $testopt tmp.c -o tmp.out >/dev/null 2>/dev/null || r=0
    if test ! -x tmp.out; then r=0; fi
    rm -f tmp.c tmp.o tmp.out
    if test $r -eq 0; then
        echo "not working"
    else
        acc="$acc $testopt"
        echo "working"
    fi
    return $r
}


# checking include file
checkinc()
{
    testcc="$1"
    testinc="$2"
    echo_n "include $testinc: "
    rm -f tmp.c tmp.o
    echo "#include <$testinc>" > tmp.c
    echo "int main() { return 1; }" >> tmp.c
    r=1
    $testcc -c tmp.c -o tmp.o >/dev/null 2>/dev/null || r=0
    if test ! -f tmp.o; then r=0; fi
    rm -f tmp.c tmp.o
    if test $r -eq 0; then echo "not found"; else echo "found"; fi
    return $r
}


# checking library
checklib()
{
    testcc="$1"
    testlib="$2"
    echo_n "library $testlib: "
    rm -f tmp.c tmp.out
    echo "int main() { return 1; }" >> tmp.c
    r=1
    $testcc tmp.c -l$testlib -o tmp.out >/dev/null 2>/dev/null || r=0
    if test ! -x tmp.out; then r=0; fi
    rm -f tmp.c tmp.o tmp.out
    if test $r -eq 0; then echo "not found"; else echo "found"; fi
    return $r
}


# checkprefix include lib
#
# tries to find a prefix needed to get the library
checkprefix()
{
    testcc="$1"
    testinc="$2"
    testlib="$3"
    testprefix="$4"
    # try without any prefix (unless the user forced a prefix)
    if test "x$testprefix" = "x"
    then
        echo "looking for $testlib without prefix"
        prefix=""
        checkinc "$testcc" "$testinc"
        if test $r -eq 1
        then
            checklib "$testcc" "$testlib"
            if test $r -eq 1
            then
                echo "library $testlib found without prefix"
                return 1
            fi
        fi
    fi
    # check with a prefix
    for prefix in $testprefix /usr/local /usr "$HOME"
    do
        echo "looking for $testlib in prefix $prefix"
        checkinc "$testcc -I$prefix/include" "$testinc"
        if test $r -eq 1
        then
            checklib "$testcc -L$prefix/lib" "$testlib"
            if test $r -eq 1
            then
                echo "library $testlib found with prefix $prefix"
                return 1
            fi
        fi
    done
    echo "library $testlib not found"
    return 0
}



# checking binaries in $PATH

searchbin()
{
    if test "x$1" = "x"; then return 0; fi
    echo_n "binary $1: "
    IFS=':'
    path=""
    for i in $PATH
    do
        if test -z "$i"; then i='.'; fi
        if test -x "$i/$1"
        then
            echo "found in $i"
            path="$i/$1"
            unset IFS
            return 1
        fi
    done
    echo "not found"
    unset IFS
    return 0
}

searchbinreq()
{
    searchbin $1
    if test $? -eq 0; then echo "required program $1 not found"; exit 1; fi
}

checkdirinpath()
{
    dir="$1"
    path="$2"
    echo_n "checking whether $1 belongs to $3: "
    # env bash -c '[[ ":'${path}':" == *":'${dir}':"* ]]';
    # if test $? -eq 1; then echo "no"; return 1; fi
    IFS=':'
    found=0
    for d in $path
    do
	if test "$d" -ef "$dir"; then found=1; fi
    done
    unset IFS;
    if test $found -eq 0; then echo "no"; return 1; fi
    echo "yes"
}

# checking support for OCaml native plugins

checkcmxs()
{
    testocamlopt="$1"
    echo_n "checking support for native plugins: "
    rm -f tmp.ml tmp.cmxs
    echo "let f = ()" >> tmp.ml
    r=1
    $testocamlopt tmp.ml -a -o tmp.cmxa >/dev/null 2>/dev/null && \
	$testocamlopt -shared -o tmp.cmxs tmp.cmxa >/dev/null 2>/dev/null || r=0
    if test ! -x tmp.cmxs; then r=0; fi
    rm -f tmp.ml tmp.cmxa tmp.cmxs tmp.a tmp.cmi tmp.cmx
    if test $r -eq 0; then
        echo "not working"
    else
        echo "working"
    fi
    return $r
}

#####################################
# tests
#######

# Flags common to c and c++ compilation
c_cxx_flags="-Wcast-qual -Wswitch -Wall -Wextra -Wundef -Wcast-align \
             -Wno-unused -Wno-unused-parameter -Wno-unused-function -fPIC"


# System-based selection of default compilers
case $(uname -s)-$(uname -r)
in
    FreeBSD-9.*)
	# NB: Select clang as default compiler on FreeBSD-9.* as gcc
	# on this system is known to trigger some bugs when compiling
	# Apron (like "junk `(%rip)' after expression").  See
	# `https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52554'
	echo "FreeBSD-9.* system detected:"\
	     "default C/C++ compilers set to clang/clang++"
	cc_compilers="$CC clang"
	cxx_compilers="$CXX clang++"
	;;
    *)
	cc_compilers="$CC cc gcc clang"
	cxx_compilers="$CXX c++ g++ clang++"
	;;
esac


# C compiler

cc="none"
for i in $cc_compilers
do
    checkcomp "$i" ""
    if test $? -eq 1; then cc="$i"; break; fi
done
if test "$cc" = "none"; then echo "no C compiler found"; exit 1; fi

acc=""
for i in $c_cxx_flags -Werror-implicit-function-declaration -Wbad-function-cast -Wstrict-prototypes -std=c99 $CFLAGS $LDFLAGS
do
    checkcomp "$cc" "$i"
done
cflags=$acc


# C++ compiler

if test $has_cxx -eq 1
then
    has_cxx=0
    for i in $cxx_compilers
    do
        checkcomp "$i" ""
        if test $? -eq 1; then has_cxx=1; cxx="$i"; break; fi
    done
fi
if test $has_cxx -eq 1
then
    acc=""
    for i in $c_cxx_flags $CXXFLAGS $LDFLAGS
    do
        checkcomp "$cxx" "$i"
    done
    cxxflags=$acc
fi


# tools

searchbinreq "ar"; ar="$path"
searchbinreq "ranlib"; ranlib="$path"
searchbinreq "sed"; sed="$path"
#searchbinreq "perl"; perl="$path"
searchbinreq "install"; install="$path"


# C libraries

if test "x$gmp_prefix" != "x"; then GMP_PREFIX="$gmp_prefix"; fi
checkprefix "$cc $cflags" gmp.h gmp "$GMP_PREFIX"
if test $? -eq 0; then echo "GMP not found, set GMP_PREFIX"; exit 1; fi
gmp_prefix="$prefix"

if test "x$mpfr_prefix" != "x"; then MPFR_PREFIX="$mpfr_prefix"; fi
checkprefix "$cc $cflags" mpfr.h mpfr "$MPFR_PREFIX"
if test $? -eq 0; then echo "MPFR not found, set MPFR_PREFIX"; exit 1; fi
mpfr_prefix="$prefix"

if test $has_cxx -eq 1 -a $has_ppl -eq 1
then
    if test "x$ppl_prefix" != "x"; then PPL_PREFIX="$ppl_prefix"; fi
    checkprefix "$cxx $cxxflags" ppl.hh ppl "$PPL_PREFIX"
    if test $? -eq 1; then has_ppl=1; fi
    ppl_prefix="$prefix"
fi


# OCaml environment

# check OCaml binaries
if test $has_ocaml -eq 1; then searchbin "ocamlc.opt"; has_ocaml=$?; ocamlc="$path"; fi
if test $has_ocaml -eq 1; then searchbin "ocamlopt.opt"; has_ocaml=$?; ocamlopt="$path"; fi
if test $has_ocaml -eq 1; then searchbin "ocamldep"; has_ocaml=$?; ocamldep="$path"; fi
if test $has_ocaml -eq 1; then searchbin "ocamllex"; has_ocaml=$?; ocamllex="$path"; fi
if test $has_ocaml -eq 1; then searchbin "ocamlyacc"; has_ocaml=$?; ocamlyacc="$path"; fi
if test $has_ocaml -eq 1; then searchbin "ocamldoc"; has_ocaml=$?; ocamldoc="$path"; fi
if test $has_ocaml -eq 1; then searchbin "ocamlmktop"; has_ocaml=$?; ocamlmktop="$path"; fi
if test $has_ocaml -eq 1; then searchbin "ocamlmklib"; has_ocaml=$?; ocamlmklib="$path"; fi
if test $has_ocaml -eq 1; then searchbin "camlidl"; has_ocaml=$?; camlidl="$path"; fi

# optional ocamlfind
if test $has_ocamlfind -eq 1
then
    has_ocamlfind=0
    if test $has_ocaml -eq 1; then searchbin "ocamlfind"; has_ocamlfind=1; ocamlfind="$path"; fi
fi

# guess prefix
if test $has_ocamlfind -eq 1
then
    caml_prefix=`$ocamlfind printconf stdlib`
    camlidl_prefix=`$ocamlfind query camlidl`
    if test "x$camlidl_prefix" = "x"; then camlidl_prefix=`$ocamlc -where`; fi
    mlgmpidl_prefix=`$ocamlfind query gmp`
    if test "x$mlgmpidl_prefix" = "x"; then mlgmpidl_prefix=`$ocamlc -where`; fi
else
    # sane default (but does not work with OPAM)
    caml_prefix=`$ocamlc -where`
    camlidl_prefix=`$ocamlc -where`
    mlgmpidl_prefix=`$ocamlc -where`
fi

# test that we can actually build plugins
if test $has_ocaml_plugins -eq 1; then checkcmxs "$ocamlopt"; has_ocaml_plugins=$?; fi

# check that the prefix is correct
if test $has_ocaml -eq 1
then
    checkinc "$cc $cflags -I$caml_prefix" caml/mlvalues.h
    has_ocaml=$?
fi
if test $has_ocaml -eq 1
then
    checkinc "$cc $cflags -I$caml_prefix -I$camlidl_prefix" caml/camlidlruntime.h
    has_ocaml=$?
fi
if test $has_ocaml -eq 1
then
    cc_cmd="$cc $cflags -I$caml_prefix -I$mlgmpidl_prefix";
    if test "x$gmp_prefix" != "x"; then cc_cmd="$cc_cmd  -I$gmp_prefix/include"; fi
    if test "x$mpfr_prefix" != "x"; then cc_cmd="$cc_cmd  -I$mpfr_prefix/include"; fi
    checkinc "$cc_cmd" gmp_caml.h
    has_ocaml=$?
fi


# Java environment

# check Java binaries
if test "x$java_prefix" != "x"; then JAVA_HOME="$java_prefix"; fi
if test "x$JAVA_HOME" != "x"; then PATH=$JAVA_HOME/bin:$PATH; fi
if test $has_java -eq 1; then searchbin "java"; has_java=$?; java="$path"; fi
if test $has_java -eq 1; then searchbin "javac"; has_java=$?; javac="$path"; fi
if test $has_java -eq 1; then searchbin "javadoc"; has_java=$?; javadoc="$path"; fi
if test $has_java -eq 1; then searchbin "jar"; has_java=$?; jar="$path"; fi

# check Java version
if test $has_java -eq 1
then
    java_version=`$java -version 2>&1 | grep version | cut -d'"' -f2 | sed 's/\(1\.\)\{0,1\}\([0-9]*\).*/\2/'`
    if test $java_version -ge 8
    then
        # new Java use javac -h
        javac_has_h=1
    else
        # old Java, use javah
        if test $has_java -eq 1; then searchbin "javah"; has_java=$?; javah="$path"; fi
    fi
fi

# check jni includes
if test $has_java -eq 1
then
    checkinc "$cc $cflags -I$JAVA_HOME/include -I$JAVA_HOME/include/linux" jni.h
    if test $? -eq 0; then echo "JNI not found, please set JAVA_HOME"; has_java=0; fi
fi


##############################################
# Custom tests
##############

# Use abolute dynamic library names under OSX when explicitly asked,
# or when the installation prefix does not belong to DYLD_LIBRARY_PATH
# nor DYLD_FALLBACK_LIBRARY_PATH or
# '$(HOME)/lib:/usr/local/lib:/lib:/usr/lib' (the default fallback).
absolute_dylib_install_names=;
if test "x$(uname -s)" = "xDarwin"
then
    if test $force_absolute_dylib_install_names -eq 1
    then
	echo "using absolute dynamic library install names as requested"
	absolute_dylib_install_names=1
    else
	libdir="${apron_prefix}/lib"
	if test "x$DYLD_FALLBACK_LIBRARY_PATH" != "x"
	then
	    fldpath="$DYLD_FALLBACK_LIBRARY_PATH"
	else
	    fldpath="$HOME/lib:/usr/local/lib:/lib:/usr/lib"
	fi
	checkdirinpath "${libdir}" "$DYLD_LIBRARY_PATH" "DYLD_LIBRARY_PATH" || \
	    checkdirinpath "${libdir}" "${fldpath}" "DYLD_FALLBACK_LIBRARY_PATH"
	if test $? -eq 1
	then
	    echo "forcing absolute dynamic library install names"
	    absolute_dylib_install_names=1
	fi
    fi
else
    if test $force_absolute_dylib_install_names -eq 1
    then
	echo "ignoring option \`-absolute-dylibs', only meaningful under OSX";
    fi
fi


##############################################
# log
#####

cat <<EOF

detected configuration:

   optional OCaml support       $has_ocaml
   optional OCamlFind support   $has_ocamlfind
   optional plugins support     $has_ocaml_plugins
   optional C++ support         $has_cxx
   optional Java support        $has_java ($java_version)
   optional PPL support         $has_ppl

   installation path            $apron_prefix
   dynamic libraries extension  $ext_dll

EOF

test "x$absolute_dylib_install_names" = "x1" && cat <<EOF
   dynamic libraries shall use absolute install names

EOF

##############################################
# generation
############

if test "$has_cxx" -eq 0; then has_cxx=; fi
if test "$has_ocaml" -eq 0; then has_ocaml=; fi
if test "$has_ocaml_plugins" -eq 0; then has_ocaml_plugins=; fi
if test "$has_java" -eq 0; then has_java=; fi
if test "$has_ppl" -eq 0; then has_ppl=; fi

cat > Makefile.config <<EOF
# generated by ./configure

HAS_OCAML = $has_ocaml
HAS_OCAMLOPT = $has_ocaml
HAS_NATIVE_PLUGINS = $has_ocaml_plugins
HAS_MPFR = 1
HAS_PPL = $has_ppl
HAS_CPP = $has_cxx
HAS_LONG_DOUBLE = 1
HAS_SHARED = 1
HAS_JAVA = $has_java

APRON_PREFIX = $apron_prefix

MLGMPIDL_PREFIX = $mlgmpidl_prefix
PPL_PREFIX = $ppl_prefix
GMP_PREFIX = $gmp_prefix
MPFR_PREFIX = $mpfr_prefix

JAVA_PREFIX = $apron_prefix/lib
JAVA      = $java
JAVAC     = $javac -Xlint:unchecked
JAVAH     = $javah
JAVAC_HAS_H = $javac_has_h
JAVADOC   = $javadoc
JAR       = $jar
java_home = ${JAVA_HOME}
jniinc    = -I${JAVA_HOME}/INCLUDE

CC = $cc
CFLAGS = -U__STRICT_ANSI__ -DNDEBUG -O3 $cflags
CFLAGS_DEBUG = -U__STRICT_ANSI__ -UNDEBUG -O0 -g $cflags

CXX = $cxx
CXXFLAGS = -U__STRICT_ANSI__ -DNDEBUG -O3 $cxxflags
CXXFLAGS_DEBUG = -U__STRICT_ANSI__ -UNDEBUG -O0 -g $cxxflags

EXT_DLL = $ext_dll

AR = $ar
RANLIB = $ranlib
SED = $sed
PERL = perl
INSTALL = $install
INSTALLd = $install -d

CAML_PREFIX = $caml_prefix
CAMLIDL_PREFIX = $camlidl_prefix
OCAMLC = $ocamlc
OCAMLOPT = $ocamlopt
OCAMLFLAGS = -g
OCAMLOPTFLAGS = -inline 20
OCAMLDEP = $ocamldep
OCAMLLEX = $ocamllex
OCAMLYACC = $ocamlyacc
OCAMLDOC = $ocamldoc
OCAMLMKTOP = $ocamlmktop
OCAMLMKLIB = $ocamlmklib
CAMLIDL = $camlidl
OCAMLFIND = $ocamlfind

# TODO: to be configured
LATEX = latex
PDFLATEX = pdflatex
DVIPDF = dvipdf
MAKEINDEX = makeindex
TEXI2ANY = texi2any

# OSX only:
ABSOLUTE_DYLIB_INSTALL_NAMES = $absolute_dylib_install_names

EOF

