#!/bin/bash

DEBUG=0

if test x"$1" = x"--debug" \
     -o x"$1" = x"--enable-debug" ; then
  DEBUG=1
  echo "Debugging enabled"
  shift
fi

if test x"$1" = x"-h" -o x"$1" = x"--help" ; then
  echo "Usage: ./configure [options]"
  echo ""
  echo "available options:"
  echo ""
  echo "  -h, --help               print this message"
  echo "  --debug, --enable-debug  enable debugging"
  echo ""
  exit 1
fi

rm -f configure.log
DEVNULL=configure.log

cc_check() {
    rm -f conftest*
    cat > conftest.cpp << EOF
#include $1
int main () { $3 return 0; }
EOF
    echo "	conftest.cpp:" >> $DEVNULL
    cat conftest.cpp >> $DEVNULL
    echo "	$CXX conftest.cpp $CXXFLAGS $LDFLAGS $2 -o conftest" >> $DEVNULL
    $CXX conftest.cpp $CXXFLAGS $LDFLAGS $2 -o conftest 1>>$DEVNULL 2>>$DEVNULL
    TMP="$?"
    rm -f conftest*
    return $TMP
}

func_check() {
  do_echo -n "Checking for $1... "
  if cc_check "$2" "$3" "$4"; then
    do_echo Yes
    return 0
  else
    do_echo No
    return 1
  fi
}

select_tool() {
    toolname=$1
    shift
    echo -n '' > conftest
    for tool in $*; do
      tool_ver="`$tool -dumpversion 2>&1`"
      if test ! "$?" -gt 0; then echo -e "$tool_ver	$tool" >> conftest; fi
    done
    if test -z "`cat conftest`"; then
      echo ""
      echo "Error: Unable to determine a suitable $toolname".
      echo "Configure cannot progress. Try installing $1."
      exit 1
    fi
    cat conftest >> $DEVNULL
    sel_tool="`sort -rn < conftest | head -n 1 | sed 's/.*	//'`"
    sel_ver="`sort -rn < conftest | head -n 1 | sed 's/	.*//'`"
    eval "$toolname"="'$sel_tool'"
    do_echo -n "$toolname=$sel_tool($sel_ver) "
}

do_echo() {
  op=""
  if test x"$1" = x"-n"; then op="$1"; shift; fi
  echo $op "$*"
  echo "$*" >> $DEVNULL
}

cpu_check() {
  do_echo -n "Checking if your CPU supports $1... "
  if grep '^\(flags\|Features\)' /proc/cpuinfo |sed 's/.*://'|tr ' ' '\012'|grep -q '^'"$2"'$'; then
    if cc_check '<stdio.h>' "$3" 'puts("ok");'; then
      OPTIM="$OPTIM $3"
      BEST_CPUFEATURE="$3"
      do_echo "Yes, using $3"
    else
      do_echo "Yes, but your compiler does not support $3"
      if [ ! "$4" = "" ]; then
        do_echo "- Using -D$4 anyway"
        OPTIM="$OPTIM -D$4"
      fi
    fi
  else
    do_echo No
  fi
}

CFLAGS=""
CPPFLAGS=""
LDFLAGS=""
OPTIM=""

do_echo -n "Determining compiler version to use... "
select_tool CXX g++    icc `(IFS=':'; for s in $PATH;do cd "$s"&&echo g++-*;done) 2>/dev/null`
select_tool CPP cpp    icc `(IFS=':'; for s in $PATH;do cd "$s"&&echo cpp-*;done) 2>/dev/null`
select_tool CC  gcc cc icc `(IFS=':'; for s in $PATH;do cd "$s"&&echo gcc-*;done) 2>/dev/null`
do_echo ""

do_echo -n "Checking if the determined compiler works... "
if cc_check '<stdio.h>' '' 'for(int a=0; a<10;++a) { for(int a=0; a<5;++a) { } } puts("ok");'; then
  do_echo Ok
else
  do_echo No
  do_echo "Error: Configure cannot figure out how to use your compiler."
  do_echo "Please try installing some recent version of gcc."
  exit 1
fi

if [ "$CC" = icc ]; then
  CPPFLAGS="$CPPFLAGS -w1"
  OPTIM="$OPTIM -inline-level=2"
  #do_echo -n "Checking if your compiler supports -ipo... "
  #if cc_check '<stdio.h>' '-ipo' 'int x,y[100];for(x=0; x<100;++x)y[x]=5;'; then
  #  #do_echo Yes
  #  #OPTIM="$OPTIM -ipo"
  #  do_echo "Yes, but not using - causes crash of ICC 11.0"
  #else
  #  do_echo No
  #fi
  
  cat > conftest.cpp << EOF
  int main() { }
EOF
  # Figure out where ICC lives, and by extension, its library paths
  ICC_PATH="`"$CC" -v conftest.cpp 2>&1 | grep mcpcom | head -n 1 | sed 's@/mcpcom.*@@'`"
  # Explicitly add ICC's libs to the LDFLAGS -- shouldn't be needed,
  #  but it is, at least when you're using ICC on a distribution that
  #  isn't supported by Intel, such as Debian on x86_64.
  LDFLAGS="$LDFLAGS -L$ICC_PATH""/lib -lirc -lstdc++"
fi

DISABLE_THREADS=""
#DISABLE_THREADS=q

HAS_OPENMP=0
do_echo -n "Checking if your compiler supports OpenMP... "
if [ "$CC" = "icc" ] && \
    cc_check '<'$DISABLE_THREADS'stdio.h>' '-openmp' 'int x,y[100];
#pragma omp parallel for
for(x=0; x<100;++x)y[x]=5;'; then
  do_echo Yes
  do_echo "- Will use OpenMP (-openmp), not checking for -pthread"
  CPPFLAGS="$CPPFLAGS -openmp"
  LDFLAGS="$LDFLAGS -openmp"
  CPPFLAGS="$CPPFLAGS -DUSE_PTHREADS=0"
  HAS_OPENMP=1

  # Needed for openmp support:
  LDFLAGS="$LDFLAGS -lguide -lpthread"
elif cc_check '<'$DISABLE_THREADS'stdio.h>' '-fopenmp' 'int x,y[100];for(x=0; x<100;++x)y[x]=5;'; then
  do_echo Yes
  do_echo "- Will use OpenMP, not checking for -pthread"
  CPPFLAGS="$CPPFLAGS -fopenmp"
  LDFLAGS="$LDFLAGS -fopenmp"
  CPPFLAGS="$CPPFLAGS -DUSE_PTHREADS=0"
  HAS_OPENMP=1
else
  do_echo No
fi

if [ "$HAS_OPENMP" = "0" ]; then
  do_echo -n "Checking if your compiler supports -pthread... "
  if cc_check '"'$DISABLE_THREADS'lib/threadfun.hh"' '-pthread' 'ThreadType t;JoinThread(t);'; then
    do_echo Yes
    CPPFLAGS="$CPPFLAGS -DUSE_PTHREADS=1 -pthread"
    LDFLAGS="$LDFLAGS -pthread"
  else
    do_echo No
    CPPFLAGS="$CPPFLAGS -DUSE_PTHREADS=0"
  fi
fi

if [ "$HAS_OPENMP" = "1" ]; then
  do_echo -n "Checking for OpenMP version... "
  rm -f conftest*
  cat > conftest.cpp << EOF
#include <stdio.h>
int main() { printf("%d\n", _OPENMP); return 0; }
EOF
  echo "	conftest.cpp:" >> $DEVNULL
  cat conftest.cpp >> $DEVNULL
  echo "	$CXX conftest.cpp $CXXFLAGS $LDFLAGS -o conftest" >> $DEVNULL
  $CXX conftest.cpp $CXXFLAGS $LDFLAGS -o conftest 1>>$DEVNULL 2>>$DEVNULL
  OPENMP_VERSION="`./conftest`"
  rm -f conftest*
  if [ "$OPENMP_VERSION" = "200805" ]; then
    echo "3.0 ($OPENMP_VERSION)"
  elif [ "$OPENMP_VERSION" = "200505" ]; then
    echo "2.5 ($OPENMP_VERSION)"
  else
    echo "Unknown ($OPENMP_VERSION)"
  fi
fi


do_echo -n "Checking for pkg-config... "
if pkg-config --version &> /dev/null; then
  do_echo Yes
else
  do_echo No
  do_echo "Warning: Cromfs configure script needs pkg-config in order"
  do_echo "to determine which other packages are installed and how"
  do_echo "to use them. Please install pkg-config."
fi

do_echo -n "Checking for fuse (dynamic)... "
fusetry="`pkg-config --cflags --libs fuse`"
if cc_check '<fuse_lowlevel.h>' "-DFUSE_USE_VERSION=25 $fusetry" ''; then
  do_echo Yes
else
  do_echo No
  do_echo "Error: Cromfs requires the Fuse userspace libraries."
  do_echo "Please try installing libfuse-dev or fuse-devel."
  exit 1
fi

do_echo -n "Checking for fuse (static)... "
fusetry="`pkg-config --cflags --libs fuse`"
if cc_check '<fuse_lowlevel.h>' "-static -DFUSE_USE_VERSION=25 $fusetry" ''; then
  do_echo Yes
  FUSE_STATIC=1
else
  do_echo No
  do_echo "Note: cromfs-driver-static will not be built, because"
  do_echo "your system does not have a statically linked Fuse library."
  do_echo "You can still use the dynamically linked cromfs-driver."
  FUSE_STATIC=0
fi

MKCROMFS_LZO_OBJ=""
HAS_LZO2=""
do_echo -n "Checking for liblzo2 (dynamic)... "
if cc_check '<lzo/lzo1x.h>' "-llzo2" ''; then
  do_echo Yes
  HAS_LZO2="-llzo2"
else
  do_echo No
fi

do_echo -n "Checking for liblzo2 (static)... "
if cc_check '<lzo/lzo1x.h>' "-Bstatic -llzo2 -Bdynamic" ''; then
  do_echo Yes
  HAS_LZO2="-Bstatic -llzo2 -Bdynamic"
else
  do_echo No
fi

if [ ! "$HAS_LZO2" = "" ]; then
  do_echo -n "Checking for assembler-optimized lzo2 functions... "
  if cc_check '<lzo/lzo_asm.h>' "$HAS_LZO2" 'lzo1x_decompress_asm_fast_safe(0,0, 0,0, 0);'; then
    do_echo Yes
    CPPFLAGS="$CPPFLAGS -DHAS_LZO2=1 -DHAS_ASM_LZO2=1"
    LDFLAGS="$LDFLAGS $HAS_LZO2"
  else
    do_echo No
    HAS_LZO2=""
  fi
fi

if [ "$HAS_LZO2" = "" ]; then
  do_echo "- In the absense of assembler-optimized liblzo2, mkcromfs will use lzo1x_1_15 (shipped)"
  CPPFLAGS="$CPPFLAGS -DHAS_LZO2=1 -DHAS_ASM_LZO2=0"
  #MKCROMFS_LZO_OBJ="../lib/lzo/lzo1x_1o.o ../lib/lzo/lzo1x_d1.o"
fi



do_echo -n "Checking for vsnprintf... "
if cc_check '<cstdio>' '' 'char Buf[10];using namespace std; va_list ap;vsnprintf(Buf,sizeof Buf,"gruu",ap);'; then
  do_echo Yes
  CPPFLAGS="$CPPFLAGS -DHAS_VSNPRINTF"
else
  do_echo No
fi


do_echo -n "Checking for lutimes... "
if cc_check '<sys/time.h>' '' 'struct timeval tv[2]; lutimes(__FILE__, tv);'; then
  do_echo Yes
  CPPFLAGS="$CPPFLAGS -DHAS_LUTIMES"
else
  do_echo No
fi



if func_check stdint.h \
   '<stdint.h>' '' 'typedef int x;'; \
   then CPPFLAGS="$CPPFLAGS -DHAS_STDINT_H"; fi

if func_check inttypes.h \
   '<inttypes.h>' '' 'typedef int x;'; \
   then CPPFLAGS="$CPPFLAGS -DHAS_INTTYPES_H"; fi

if func_check readdir_r \
   '<dirent.h>' '' 'DIR*dir=opendir(".");dirent e,*ep;readdir_r(dir,&e,&ep);'; \
   then CPPFLAGS="$CPPFLAGS -DHAS_READDIR_R"; fi

if func_check uint16_t \
   '<stdint.h>' '' 'typedef uint16_t x;'; \
   then CPPFLAGS="$CPPFLAGS -DHAS_UINT16_T"; fi

if func_check u_int16_t \
   '<stdint.h>' '' 'typedef u_int16_t x;'; \
   then CPPFLAGS="$CPPFLAGS -DHAS_U_INT16_T"; fi

if func_check __uint16_t \
   '<stdint.h>' '' 'typedef _uint16_t x;'; \
   then CPPFLAGS="$CPPFLAGS -DHAS___UINT16_T"; fi

if func_check long\ long \
   '<stdint.h>' '' 'typedef long long x;'; \
   then CPPFLAGS="$CPPFLAGS -DHAS_LONG_LONG"; fi

if func_check sys/types.h \
   '<sys/types.h>' '' 'typedef int x;'; \
   then CPPFLAGS="$CPPFLAGS -DHAS_SYS_TYPES_H"; fi

WARNINGS=""
CWARNINGS=""
CXXWARNINGS=""

OPTIM="$OPTIM -O3"

if [ "$CC" = "icc" ]; then
  #do_echo -n "Checking if your compiler supports -pch... "
  #if cc_check '<stdio.h>' '-pch' 'int x,y[100];for(x=0; x<100;++x)y[x]=5;'; then
  #  do_echo Yes
  #  OPTIM="$OPTIM -pch"
  #else
  #  do_echo No
  #fi
  true
else
  LDFLAGS="$LDFLAGS -Xlinker --gc-sections"

  do_echo -n "Checking if your compiler supports -minline-stringops-dynamically... "
  if cc_check '<string.h>' '-minline-stringops-dynamically' 'char buf1[64],buf2[80]="kissa"; memcpy(buf1,buf2,sizeof(buf2)-strlen(buf2));'; then
    do_echo Yes
    OPTIM="$OPTIM -minline-stringops-dynamically"
  else
    do_echo No
  fi
  
  # Removed from the list:
  # -ftree-switch-conversion (new in GCC 4.4, automatically turned on by -O2)
  # -ftree-vectorize (new in GCC 4.0, automatically turned on by -O3 at least since GCC 4.3)
  
  # -fwhole-program (new in GCC-4.4, makes compiler assume that
  #                  the included source files consist of entire
  #                  program, messing link semantics)

  T_OPTIM="\
    -ffast-math -mrecip -fvpt -ffunction-cse -ffunction-sections -fdata-sections"
  for s in $T_OPTIM;do
    do_echo -n "Checking if your compiler supports $s... "
    if cc_check '<stdio.h>' "$s" 'int x,y[100];for(x=0; x<100;++x)y[x]=5;'; then
      do_echo Yes
      OPTIM="$OPTIM $s"
    else
      do_echo No
    fi
  done
  
  #-fconserve-stack
  
  T_WARNINGS="-Wall \
    -Wundef \
    -Wcast-qual \
    -Wpointer-arith \
    -Wconversion \
    -Wwrite-strings \
    -Wsign-compare \
    -Wredundant-decls \
    -Winit-self \
    -Wextra \
    -Wsequence-points \
    -Wparentheses \
    -Wcast-align -Wformat \
    -Wno-conversion"
  T_CWARNINGS="-Waggregate-return -Wshadow -Winline \
    -Wstrict-prototypes \
    -Wmissing-prototypes"
  T_CXXWARNINGS="-Woverloaded-virtual -Wno-non-virtual-dtor"

  for s in $T_WARNINGS;do
    do_echo -n "Checking if your compiler supports $s... "
    if cc_check '<stdio.h>' "$s" ''; then
      do_echo Yes
      WARNINGS="$WARNINGS $s"
    else
      do_echo No
    fi
  done
  for s in $T_CWARNINGS;do
    do_echo -n "Checking if your compiler supports $s... "
    if cc_check '<stdio.h>' "$s" ''; then
      do_echo Yes
      CWARNINGS="$CWARNINGS $s"
    else
      do_echo No
    fi
  done
  for s in $T_CXXWARNINGS;do
    do_echo -n "Checking if your compiler supports $s... "
    if cc_check '<stdio.h>' "$s" ''; then
      do_echo Yes
      CXXWARNINGS="$CXXWARNINGS $s"
    else
      do_echo No
    fi
  done
fi  

(echo "Your CPU has these features:"
 grep flags /proc/cpuinfo | uniq | sed 's/.*://' | tr ' ' '\012'|sort|grep .|(fmt -w60||cat)|sed 's/^/- /'
) >> $DEVNULL

if [ ! "$CC" = "icc" ]; then
  cpu_check MMX   mmx   -mmmx   __MMX__
  cpu_check 3dnow 3dnow -m3dnow
  cpu_check SSE   sse   -msse   __SSE__
  cpu_check SSE2  sse2  -msse2  __SSE2__
  cpu_check SSE3  sse3  -msse3  __SSE3__
  cpu_check SSSE3 ssse3 -mssse3 __SSSE3__
  #cpu_check ABM   abm   -abm    __SSE4_2__
  cpu_check sahf  lahf_lm -msahf HAS_SAHF
  cpu_check VFP   vfp   -mfpu=vfp __VFP_FP__
else
  # ICC can only take one (1) cpu feature flag, so we test these options
  # in age succession and choose the options from the last succeeding test.
  # We use the -ax options rather than the -x options so that the code
  # will still run on processors lacking those features.
  BEST_CPUFEATURE=""
  OPTIM_BACKUP="$OPTIM"
  cpu_check SSE   sse   -xK            __SSE__
  cpu_check SSE2  sse2  -xW            __SSE2__
  cpu_check SSE3  sse3  "-xO -msse3"   __SSE3__
  cpu_check SSSE3 ssse3 "-xT -mssse3"  __SSSE3__
  OPTIM="$OPTIM_BACKUP $BEST_CPUFEATURE"
fi

do_echo "Updating Makefile.sets ..."

if [ "$DEBUG" = "1" ]; then
  OPTIM="-O1 -fno-inline"
  do_echo -n "Checking if your compiler supports -ggdb3... "
  if cc_check '<stdio.h>' "-ggdb3" ''; then
    OPTIM="$OPTIM -ggdb3"
    echo "Yes"
  else
    OPTIM="$OPTIM -g"
    echo "No"
  fi
fi

DATE="`LC_ALL=C date`"
UNAME="`uname -a`"
sed_cmd=""
for s in CC CPP CXX OPTIM CPPFLAGS LDFLAGS FUSELIBS DATE UNAME WARNINGS CWARNINGS CXXWARNINGS; do
  eval value=\"\$$s\"
  sed_cmd="$sed_cmd;s{CONFIG_$s}$value"
done

sed "$sed_cmd" < Makefile.sets.in > Makefile.sets
echo "FUSE_STATIC=$FUSE_STATIC"  >> Makefile.sets

echo "MKCROMFS_LZO_OBJ=$MKCROMFS_LZO_OBJ" >> Makefile.sets

cp -p Makefile.sets util/
cp -p Makefile.sets  lib/

for dir in . lib util; do
  rm $dir/.depend $dir/.libdepend; make -C $dir .depend
done &> /dev/null
