#!/bin/sh
# Copyleft valabind 2009-2017 pancake

LANG=$1
MOD=$2

show_help () {
  echo "Usage: valabind-cc [lang] [module-name] [-flags] vapifile .."
  echo "Example: valabind-cc python r_bp -I/usr/include/r_bp r_bp.vapi"
  echo "  lang: ctypes, python, dlang, nodejs, ocaml, guile, go, ruby,"
  echo "        perl, lua, java, csharp, ..."
  echo "  --help,-h      show this help message"
  echo "  --version      show version of valabind"
  echo "  --vapidir=dir  specify path to vapi files"
  echo "  --glib         assume vapi source is glib/gobject based"
  echo "  --test [lang]  test if it is possible to build"
  echo "  -x             generate C++ swig code"
  echo "  -X             output C++ instead of SWIG interface"
  echo "  -I[path]       add includepath for SWIGFLAGS and CFLAGS"
  echo "  -V[path]       add includepath for vapi files"
  echo "  -L[path]       append library path to LDFLAGS"
  echo "  -l[lib]        append to LDFLAGS to link a library"
  echo "  -C             do not compile, just let the .c/.cxx and .i files"
  echo "  -n             do not generate .i/.c/.cxx code, but compile it"
  echo "  -N[nspace]     include namespace in the output"
  echo "  -D[SYMBOL]       define vala symbol Symbol"
  echo "  --nolibpython  do not include libpython in Python flags"
  echo " Environment:"
  echo "  VALABIND_DEBUG if not empty show stderr of commands"
  echo "  PYTHON_CONFIG  path to python-config program (select py2 or py3)"
  echo "  SWIGFLAGS      extra flags to be passed to swig"
  echo "  SOEXT          force extension for shared library (so, dll, dylib)"
  echo "  SWIG           path to swig program"
  exit 0
}

OMOD=${MOD}
[ -z "${SWIG}" ] && SWIG=swig
[ -z "${LANG}" ] && show_help
[ -z "${CC}" ] && CC=gcc
[ -z "${CXX}" ] && CXX=g++
COMPILE=Yes
ARG_VAPIDIR=""
EXT="c"
CXXOUT=0
NOGEN=0
if [ -z "${SOEXT}" ]; then
  if [ -n "`uname -a | grep -i darwin`" ]; then
    SOEXT="dylib"
  elif [ -n "`echo ${CC} | grep mingw`" ]; then
    SOEXT="dll"
  else
    SOEXT="so"
  fi
fi
if [ -z "${VALABIND_DEBUG}" ]; then
  NULLPIPE=">/dev/null"
else
  NULLPIPE=""
fi

use_cxx() {
    CC="${CXX}"
    EXT="cxx"
    CFLAGS="${CFLAGS} ${CXXFLAGS}"
    SWIGFLAGS="-c++ ${SWIGFLAGS}"
    VALABINDFLAGS="-x ${VALABINDFLAGS}"
}

TEST=0
case "$1" in
"--test")
  TEST=1
  LANG=$2
  ;;
"--version")
  printf "valabind " ; valabind --version
  ${SWIG} -version | grep SWIG
  ${CC} --version | grep ${CC}
  exit 0
  ;;
"--help"|"-h")
  show_help
  ;;
esac

SWIG="${SWIG} -small"
case "${LANG}" in
ctypes)
  python2 --version >/dev/null 2>&1 || \
  python --version > /dev/null 2>&1 || \
  exit 1
  ;;
dlang)
  dmd --help >/dev/null 2>&1 || \
  ldc2 --help >/dev/null 2>&1 || \
  exit 1
  ;;
nodejs|node|node-ffi)
  node --version >/dev/null 2>&1 || exit 1
  ;;
ocaml)
  use_cxx
  echo "SWIG is buggy. Please set in ocamldec.swg the following line:"
  echo "#define caml_array_length swig_caml_array_length"
  OCAMLPATH=`ocamlc -where`
  CFLAGS="${CFLAGS} -I${OCAMLPATH}/ -Dcaml_array_length=caml_array_length__"
  LDFLAGS="${LDFLAGS} -L${OCAMLPATH} -lcamlrun"
  ;;
guile)
  use_cxx
  CFLAGS="${CFLAGS} `guile-config compile 2>/dev/null`"
  LDFLAGS="${LDFLAGS} `guile-config link 2>/dev/null`"
  ;;
python)
  use_cxx
  LDFLAGS="${LDFLAGS} -L/usr/local/lib -L/usr/pkg/lib"
  if [ -n "`echo ${CXX} | grep mingw`" ]; then
    CFLAGS="${CFLAGS} -I${HOME}/.wine/drive_c/Python27/include"
    LDFLAGS="${LDFLAGS} -L${HOME}/.wine/drive_c/Python27/libs -lpython27"
  else
    PYCFG=""
    for a in ${PYTHON_CONFIG} python-config python2-config python3-config ; do
      $a --help >/dev/null 2>&1
      if [ $? = 0 ]; then
        PYCFG=$a
        break
      fi
    done
    if [ -z "$PYCFG" ]; then
      echo "No valid PYTHON_CONFIG command found" >&2
      exit 1
    fi
    CFLAGS="${CFLAGS} `$PYCFG --cflags | sed -e 's,-arch [^ ]*,,g'`"
    LDFLAGS="${LDFLAGS} `$PYCFG --ldflags| sed -e 's,-arch [^ ]*,,g'`"
  fi
  OMOD="_${MOD}"
  # XXX SWIGFLAGS="${SWIGFLAGS} -threads"
  ;;
ruby)
  if [ "`ruby --version 2>/dev/null | grep 1.8`" ]; then
    RB_CFLAGS=`ruby -e 'require "mkmf"; print "-I" + RbConfig::CONFIG["archdir"];' 2>/dev/null`
  else
  if [ "`ruby --version 2>/dev/null | grep 1.9`" ]; then
    RB_CFLAGS=`ruby -e 'require "mkmf"; a=RbConfig::CONFIG["rubyhdrdir"]; print "-I#{a} -I#{a}/" + RbConfig::CONFIG["arch"];'`
  else
  if [ "`ruby --version 2>/dev/null | grep 2.0`" ]; then
    RB_CFLAGS=`ruby -e 'require "mkmf"; a=RbConfig::CONFIG["rubyhdrdir"]; print "-I#{a} -I#{a}/" + RbConfig::CONFIG["arch"];'`
  else
  if [ "`ruby --version 2>/dev/null | grep 2.1`" ]; then
    RB_CFLAGS=`ruby -e 'require "mkmf"; a=RbConfig::CONFIG["rubyhdrdir"]; print "-I#{a} -I#{a}/" + RbConfig::CONFIG["arch"];'`
  fi ; fi ; fi ; fi
  CFLAGS="${CFLAGS} ${RB_CFLAGS}"
  ;;
perl)
  LC_ALL=C # fix anoying perl warning
  export LC_ALL
  CFLAGS="${CFLAGS} `perl -MExtUtils::Embed -e ccopts 2>/dev/null | sed -e 's,-arch [^ ]*,,g'`"
  LDFLAGS="${LDFLAGS} `perl -MExtUtils::Embed -e ldopts 2>/dev/null | sed -e 's,-arch [^ ]*,,g'`"
  ;;
java)
  if [ -n "$JAVA_HOME" ]; then
    [ "`uname`" = Darwin ] && osname=darwin || osname=linux
    CFLAGS="${CFLAGS} -I${JAVA_HOME}/include -I${JAVA_HOME}/include/$osname"
  elif [ -f /opt/java/include/jni.h ]; then
    CFLAGS="${CFLAGS} -I/opt/java/include -I/opt/java/include/linux"
  fi
  ;;
php5)
  CFLAGS="${CFLAGS} `php-config --includes 2>/dev/null` `pkg-config --libs libpng 2>/dev/null`"
  LDFLAGS="${LDFLAGS} `php-config --libs 2>/dev/null`"
  ;;
lua)
  SOEXT=so
  LUAPKG=`pkg-config --list-all|awk '/lua|lua-/{print $1;}'`
  if [ -n "${LUAPKG}" ]; then
    CFLAGS="${CFLAGS} `pkg-config --cflags ${LUAPKG}`"
    LDFLAGS="${LDFLAGS} `pkg-config --libs ${LUAPKG}`"
  fi
  ;;
go)
  ;;
csharp)
  VALABINDFLAGS="--camel-getters ${VALABINDFLAGS}"
  ;;
node-swig)
  SWIGFLAGS="-javascript"
  CFLAGS="${CFLAGS} -I/usr/include/node"
  ;;
esac

shift
shift

while : ; do
  [ -z "$1" ] && break
  if [ "`echo $1 | grep -- '^-I'`" ]; then
    CFLAGS="${CFLAGS} $1"
    SWIGFLAGS="$1 ${SWIGFLAGS}"
    VALABINDFLAGS="`echo $1|sed -e 's,^-I,-I ,'` ${VALABINDFLAGS}"
  elif [ "`echo $1 | grep -- '^-V'`" ]; then
    CFLAGS="${CFLAGS} $1"
    VALABINDFLAGS="`echo $1|sed -e 's,^-V,-V ,'` ${VALABINDFLAGS}"
  elif [ "`echo $1 | grep -- '--vapidir'`" ]; then
    ARG_VAPIDIR="`echo $1|sed -e 's,=, ,'`"
  elif [ "`echo $1 | grep -- '^-x'`" ]; then
    use_cxx
  elif [ "`echo $1 | grep -- '^-n'`" ]; then
    NOGEN=1
  elif [ "`echo $1 | grep -- '^-N'`" ]; then
    VALABINDFLAGS="`echo $1|sed -e 's,^-N,-N ,'` ${VALABINDFLAGS}"
  elif [ "`echo $1 | grep -- '^-X'`" ]; then
    EXT="cxx"
    CXXOUT=1
  elif [ "`echo $1 | grep -- '^-l'`" ]; then
    LDFLAGS="$1 ${LDFLAGS}"
  elif [ "`echo $1 | grep -- '^--glib'`" ]; then
    SWIGFLAGS="$1 ${SWIGFLAGS}"
  elif [ "`echo $1 | grep -- '^-L'`" ]; then
    LDFLAGS="$1 ${LDFLAGS}"
  elif [ "`echo $1 | grep -- '^-C'`" ]; then
    COMPILE=""
  elif [ "`echo $1 | grep -- '^-pthread'`" ]; then
    echo ignored $1
  elif [ "`echo $1 | grep -- '^-D'`" ]; then
    VALABINDFLAGS="`echo $1|sed -e 's,^-D,-D ,'` ${VALABINDFLAGS}"
  elif [ "`echo $1 | grep -- '^--nolibpython'`" ]; then
    SEDFLAGS="-r"
    if [ -z "`sed --version 2>/dev/null | grep GNU`" ]; then
      SEDFLAGS="-E"
    fi
    LDFLAGS="$(echo ${LDFLAGS} | sed ${SEDFLAGS} 's,-lpython[0-9.]+,,g')"
  else
    FILES="$1 ${FILES}"
  fi
  shift
done

SWIGCPP="-DG_BEGIN_DECLS -DG_END_DECLS -DG_GNUC_CONST -DSWIG_PYTHON_SILENT_MEMLEAK"

# strip problematic cflags. can be problematic if not used
CFLAGS="`echo "${CFLAGS}" | sed -e 's,-pie,,g' -e 's,-PIE,,g'`"
LDFLAGS="`echo "${LDFLAGS}" | sed -e 's,-pie,,g' -e 's,-PIE,,g'`"

if [ "$CXXOUT" = 1 ]; then
  echo valabind -X ${VALABINDFLAGS} ${ARG_VAPIDIR} -o ${MOD}.i -m ${MOD} ${FILES}
  valabind -X ${VALABINDFLAGS} ${ARG_VAPIDIR} -o ${MOD}.cxx -m ${MOD} ${FILES} || exit 1
  #TODO:
  #if [ -n "${COMPILE}" ]; then
  #  echo ${CC} ${MOD}.cxx -fPIC -shared ${MOD}_wrap.${EXT} ${CFLAGS} -o ${OMOD}.${SOEXT} ${LDFLAGS}
  #  ${CC} $@ -fPIC -shared ${MOD}_wrap.${EXT} ${CFLAGS} -o ${OMOD}.${SOEXT} ${LDFLAGS} || exit 1
  #fi
#  echo ${CXX} ${MOD}.cxx $@ -fPIC -shared ${MOD}.cxx ${CXXFLAGS} ${CFLAGS} -o ${OMOD}.${SOEXT} ${LDFLAGS}
#  ${CXX} ${MOD}.cxx $@ -fPIC -shared ${MOD}.cxx ${CXXFLAGS} ${CFLAGS} -o ${OMOD}.${SOEXT} ${LDFLAGS} > /dev/null 2>&1
elif [ "$TEST" = 1 ]; then
  case "${LANG}" in
  ctypes)
    python2 --version > /dev/null 2>&1 || \
    python --version > /dev/null 2>&1 || \
    exit 1
    ;;
  dlang)
    dmd --help >/dev/null 2>&1 || \
    ldc2 --help >/dev/null 2>&1 || \
    exit 1
    ;;
  "nodejs"|"node"|"node-ffi")
    exec node --version > /dev/null 2>&1
    ;;
  *)
    DIR=`mktemp -d /tmp/tmp.XXXXXX`
    if [ ! $? = 0 ]; then
      echo "Cannot create temporary directory"
      exit 1
    fi
    cd ${DIR}
    MOD=test # hack to fix guile
    echo "%module ${MOD}" > ${MOD}.i
    eval echo ${SWIG} -O -o ${MOD}_wrap.${EXT} ${SWIGCPP} ${SWIGFLAGS} -${LANG} ${MOD}.i ${NULLPIPE}
    eval ${SWIG} -O -o ${MOD}_wrap.${EXT} ${SWIGCPP} ${SWIGFLAGS} -${LANG} ${MOD}.i ${NULLPIPE}
    if [ ! $? = 0 ]; then rm -rf ${DIR} ; exit 1 ; fi
    if [ "${EXT}" = cxx ]; then
      CFLAGS="${CFLAGS} ${CXXFLAGS}"
    fi
    eval echo ${CC} $@ -fPIC -shared ${MOD}_wrap.${EXT} ${CFLAGS} -o ${OMOD}.${SOEXT} ${LDFLAGS} ${NULLPIPE}
    eval ${CC} $@ -fPIC -shared ${MOD}_wrap.${EXT} ${CFLAGS} -o ${OMOD}.${SOEXT} ${LDFLAGS} ${NULLPIPE}
    if [ ! $? = 0 ]; then rm -rf ${DIR} ; exit 1 ; fi
    rm -rf ${DIR}
    ;;
  esac
else
  case "${LANG}" in
  "ctypes")
    eval echo valabind --ctypes ${VALABINDFLAGS} ${ARG_VAPIDIR} -o ${MOD}.py -m ${MOD} ${FILES}
    eval valabind --ctypes ${VALABINDFLAGS} ${ARG_VAPIDIR} -o ${MOD}.py -m ${MOD} ${FILES} ${NULLPIPE}
    exit $?
    ;;
  "nodejs"|node|"node-ffi")
    eval echo valabind --node-ffi ${VALABINDFLAGS} ${ARG_VAPIDIR} -o ${MOD}.js -m ${MOD} ${FILES}
    eval valabind --node-ffi ${VALABINDFLAGS} ${ARG_VAPIDIR} -o ${MOD}.js -m ${MOD} ${FILES} ${NULLPIPE}
    exit $?
    ;;
  *)
    [ "${LANG}" = node-swig ] && LANG=node
    if [ "${NOGEN}" = 0 ]; then
      echo valabind --swig ${VALABINDFLAGS} ${ARG_VAPIDIR} -o ${MOD}.i -m ${MOD} ${FILES}
      valabind --swig ${VALABINDFLAGS} ${ARG_VAPIDIR} -o ${MOD}.i -m ${MOD} ${FILES} || exit 1
      eval echo ${SWIG} -O -o ${MOD}_wrap.cxx ${SWIGCPP} ${SWIGFLAGS} -${LANG} ${MOD}.i
      ${SWIG} -O -o ${MOD}_wrap.cxx ${SWIGCPP} ${SWIGFLAGS} -${LANG} ${MOD}.i || exit 1
    fi
    if [ -n "${COMPILE}" ]; then
      # Damn Python flags!
      CFLAGS="`echo ${CFLAGS} | sed -e 's,-mno[^\ ]*,,g' -e 's,-f[^\ ]*,,g'`"
      LDFLAGS="`echo ${LDFLAGS} | sed -e 's,-pagezero_size [^\ ]*,,g'`"
      LDFLAGS="`echo ${LDFLAGS} | sed -e 's,-image_base [^\ ]*,,g'`"
      if [ "${EXT}" = cxx ]; then
        CFLAGS="${CFLAGS} ${CXXFLAGS}"
      fi
      echo ${CC} $@ -fPIC -shared ${MOD}_wrap.${EXT} ${SWIGCPP} ${CFLAGS} -o ${OMOD}.${SOEXT} ${LDFLAGS}
      ${CC} $@ -fPIC -shared ${MOD}_wrap.${EXT} ${SWIGCPP} ${CFLAGS} -o ${OMOD}.${SOEXT} ${LDFLAGS} || exit 1
    fi
  esac
fi
