#! /bin/sh

# configuration script for mlgmpidl
# based on the configure script from 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
  -no-ocamlfind        disable OCamlfind support
  -no-native-plugins   do not build native plugins
  -disable-profiling   disable compilation of profiling version
  -absolute-dylibs     force absolute library names (OSX only)

Environment variables that affect configuration:
  CC                   C compiler to use (default: gcc)
  CFLAGS               extra flags to pass to the C compiler
  LDFLAGS              extra link flags
  GMP_PREFIX           where to find the GMP library
  MPFR_PREFIX          where to find the MPFR library

EOF
    exit
}

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

mlgmpidl_prefix=/usr/local;
has_cxx=1;
has_ppl=1;
has_ocamlfind=1;
has_native_plugins=1;
enable_prof=1;
force_absolute_dylib_install_names=0;
while : ; do
    case "$1" in
        "") 
            break;;
        -prefix|--prefix)
            mlgmpidl_prefix="$2";
            shift;;
        -gmp-prefix|--gmp-prefix)
            gmp_prefix="$2";
            shift;;
        -mpfr-prefix|--mpfr-prefix)
            mpfr_prefix="$2";
            shift;;
        -no-ocamlfind|--no-ocamlfind)
            has_ocamlfind=0;;
        -no-native-plugins|--no-native-plugins)
            has_native_plugins=0;;
	-disable-profiling)
	    enable_prof=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'
}

info () { echo "$1"; }
err () { echo "$1"; exit 1; }

# 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 err "required program $1 not found"; 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"
}

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

c_flags="-Wcast-qual -Wswitch -Wall -Wextra -Wundef -Wcast-align -Wno-unused -Wno-unused-parameter -Wno-unused-function -fPIC"


# C compiler

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

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


# 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 err "GMP not found, set GMP_PREFIX"; 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 err "MPFR not found, set MPFR_PREFIX"; fi
mpfr_prefix="$prefix"

# OCaml environment

# check OCaml binaries
has_ocaml=1
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 "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 -ne 1; then err "OCaml not found"; fi

if test $has_ocaml -eq 1; then searchbin "camlidl"; has_ocaml=$?; camlidl="$path"; fi
if test $has_ocaml -ne 1; then err "OCamlIDL not found"; 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

# 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
fi
if test $has_ocaml -ne 1; then err "OCaml not found"; fi

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

overs=$($ocamlc -version);
case "${overs}" in
    [1-2].*|3.0*|3.11.*|3.12.0)
    	err "OCaml version found is ${overs}: OCaml >= 3.12.1 is required.";;
    *)
	:;;
esac

# Profiling:
cprof_flags="";
if test $enable_prof -eq 1
then
    echo -n "checking whether to enable profiling: "
    case "${overs}" in
	4.08.[1-9]*|4.09.*|4.[1-9]*)
	    echo "only available up to OCaml 4.08.0 (<= ${overs})";
	    enable_prof=0;;
	*)
	    ocaml_prof="$($ocamlc -config | sed -e '/^profiling:/!d; s/^[^:]*: *//;')"
	    if test -n "$ocaml_prof" -a "$ocaml_prof" = "false"
	    then
		echo "not supported"
		enable_prof=0
	    else
		echo "supported"
		cprof_flags="$($ocamlc -config | $sed -e '/^cc_profile:/!d; s/^[^:]*: *//;')"
		if test "x${cprof_flags}" != "x"
		then
		    echo "profiling flags provided by the ocaml system: ${cprof_flags}"
		    checkcomp "$cc" "${cprof_flags}"
		fi
	    fi;;
    esac
fi


# Extension for dynamic libraries
ext_dll="";
echo -n "finding extension for dynamic libraries: "
ext_dll="$($ocamlc -config | sed -e '/^ext_dll:/!d; s/^[^:]*: *//;')"
echo $ext_dll


# 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="${mlgmpidl_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:

   OCaml version                $overs
   optional OCamlFind support   $has_ocamlfind
   optional native plugins      $has_native_plugins
   optional profiling version   $enable_prof

   installation path            $mlgmpidl_prefix

EOF

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

EOF

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

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

HAS_SHARED = 1
HAS_OCAMLOPT = 1
ENABLE_PROF = $enable_prof

MLGMPIDL_PREFIX = $mlgmpidl_prefix

GMP_PREFIX = $gmp_prefix
MPFR_PREFIX = $mpfr_prefix

CC = $cc
CFLAGS = -U__STRICT_ANSI__ -DNDEBUG -O3 $cflags
CFLAGS_DEBUG = -U__STRICT_ANSI__ -UNDEBUG -O0 -g $cflags
CFLAGS_PROF = -U__STRICT_ANSI__ -UNDEBUG -O3 $cprof_flags $cflags
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 = -annot -g
OCAMLOPTFLAGS = -annot -inline 20
OCAMLDEP = $ocamldep
OCAMLDOC = $ocamldoc
OCAMLMKTOP = $ocamlmktop
OCAMLMKLIB = $ocamlmklib
CAMLIDL = $camlidl
OCAMLFIND = $ocamlfind

# TODO: to be configured
LATEX = latex
DVIPDF = dvipdf
MAKEINDEX = makeindex

HAS_NATIVE_PLUGINS = $has_native_plugins

# OSX only:
ABSOLUTE_DYLIB_INSTALL_NAMES = $absolute_dylib_install_names

EOF
