#!/bin/bash
set -e

# The Android API level from
# https://developer.android.com/studio/releases/platforms
API_LEVEL=21
PLATFORM=android-${API_LEVEL}

# We only build a subset of the reSIProcate stack for Android.
# Here we specify which directories we attempt to build.
PROJECTS="rutil resip/stack resip/dum"

# This is a tree where we place the compiled libraries
# and also an Android.mk for the Android SDK to use when
# building an app.
NDK_DIST=${HOME}/ndk-prebuilt
PROJECT=resip
PROJECT_DIST=${NDK_DIST}/${PROJECT}

# This directory contains files with settings for each
# architecture we build.
# The detailed list of supported architectures (Android ABI)
# is here:
# https://developer.android.com/ndk/guides/abis
MODS_DIR=build/android/modulations

if [ -z "${NDK_HOME}" ];
then
  echo "Please set NDK_HOME"
  exit 1
fi

if [ ! -d ${MODS_DIR} ];
then
  echo "Can't find directory ${MODS_DIR}"
  exit 1
fi

# This is where we download OpenSSL to be compiled
# with the same toolchain.
OPENSSL_URL=https://www.openssl.org/source/openssl-1.1.1l.tar.gz

if [ "${BUILD_OPENSSL}" == 1 ];
then
  OPENSSL_PREBUILT=`mktemp -d`
  RESIP_BUILD_DIR="`pwd`"
  cd ${OPENSSL_PREBUILT}
  wget ${OPENSSL_URL}
  OPENSSL_TGZ=`echo ${OPENSSL_URL} | tr '/' '\n' | tail -1`
  tar xzf ${OPENSSL_TGZ}
  OPENSSL_DIR_BASE=`basename ${OPENSSL_TGZ} .tar.gz`
  OPENSSL_DIR=`readlink -f ${OPENSSL_DIR_BASE}`
  cd "${RESIP_BUILD_DIR}"
fi

# Determine how many CPU cores are available for parallel compilation
CPUS=`cat /proc/cpuinfo | grep -c ^proc`
PAR=`expr $CPUS + 1`

# Temporary directory used for make install (DESTDIR)
STAGE_PREBUILT=`mktemp -d`

function cleanup {
  # Remove compiled artifacts
  if [ ! -z "${STAGE_PREBUILT}" ];
  then
    rm -rf "${STAGE_PREBUILT}"
  fi
  # Remove our transient toolchain
  if [ ! -z "${MY_NDK}" ];
  then
    rm -rf "${MY_NDK}"
  fi
}

trap cleanup EXIT

for MOD_SRC in ${MODS_DIR}/* ;
do

  echo "Trying modulation ${MOD_SRC} ..."
  MOD_NAME=`basename ${MOD_SRC}`

  export CPPFLAGS=""
  export CXXFLAGS=""
  export LDFLAGS=""

  source ${MOD_SRC}

  OPENSSL_NDK_DIST=${NDK_DIST}/openssl/${MOD_NAME}
  # Build OpenSSL for this architecture if requested to do so
  if [ -z "${OPENSSL_DIR}" ];
  then
    OPENSSL_HEADER_CHECK=${OPENSSL_NDK_DIST}/include/openssl/opensslv.h
    if [ ! -e ${OPENSSL_HEADER_CHECK} ];
    then
      echo "Could not find ${OPENSSL_HEADER_CHECK} - please try setting BUILD_OPENSSL=1"
      exit 1
    fi
  else
    export OPENSSL_INSTALL=${OPENSSL_DIR}/../install-${MOD_ARCH}
    (
      cd ${OPENSSL_DIR}
      export ANDROID_NDK_HOME=${NDK_HOME}
      PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$ANDROID_NDK_HOME/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin:$PATH
      if [ ${MOD_ARCH} == x86 ];
      then
        ./Configure android-${MOD_ARCH} -D__ANDROID_API__=${API_LEVEL} 386
      else
        ./Configure android-${MOD_ARCH} -D__ANDROID_API__=${API_LEVEL}
      fi
      # make sure builds for other architectures are cleaned up before
      # we begin
      make clean
      make -j${PAR}
      make -j${PAR} DESTDIR=${OPENSSL_INSTALL} install
      mkdir -p ${OPENSSL_NDK_DIST}
      # store a permanent copy for future use
      cp -r ${OPENSSL_INSTALL}/usr/local/include ${OPENSSL_INSTALL}/usr/local/lib/* ${OPENSSL_NDK_DIST}
    )
  fi

  # This is a target triplet, it is the argument to the --host parameter
  # of GNU configure
  # https://www.gnu.org/software/automake/manual/html_node/Cross_002dCompilation.html
  # https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.70/html_node/Specifying-Target-Triplets.html
  export CROSS_COMPILE

  if [ $API_LEVEL -lt 20 ];
  then
    # and for GNU tools, CROSS_COMPILE is also the prefix added to the filenames of tools for that
    # cross-compile.
    #export TOOLCHAIN_PREFIX=${CROSS_COMPILE}

    # We use the script provided by the NDK to make a standalone toolchain
    # in the temporary location
    # A standalone toolchain combines the following:
    # - the compiler for the target CPU
    # - the headers and system libraries for the target Android API level
    # https://developer.android.com/ndk/guides/standalone_toolchain
    MY_NDK=`mktemp -d`
    echo "Creating a toolchain in ${MY_NDK}"
    ${NDK_HOME}/build/tools/make-standalone-toolchain.sh --platform=${PLATFORM} \
      --install-dir=${MY_NDK} --system=linux-x86_64 --arch=${MOD_ARCH}

    # File locations for the toolchain we just built:
    export SYSROOT=${MY_NDK}/sysroot
    export PATH=${MY_NDK}/bin:$PATH

    # Names of the tools we are using, configure reads these from
    # the environment.
    export CPP=${TOOLCHAIN_PREFIX}-cpp
    export AR=${TOOLCHAIN_PREFIX}-ar
    export AS=${TOOLCHAIN_PREFIX}-as
    export NM=${TOOLCHAIN_PREFIX}-nm
    export CC=${TOOLCHAIN_PREFIX}-gcc
    export CXX=${TOOLCHAIN_PREFIX}-g++
    export LD=${TOOLCHAIN_PREFIX}-ld
    export RANLIB=${TOOLCHAIN_PREFIX}-ranlib

    CXX_STL="-lgnustl_shared"
  else
    # newer CLang build

    # based on these instructions:
    # https://developer.android.com/ndk/guides/other_build_systems#autoconf
    export TOOLCHAIN=${NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64
    export TARGET=${CROSS_COMPILE}

    export SYSROOT=${MY_NDK}/sysroot

    export AR=$TOOLCHAIN/bin/llvm-ar
    export CC=$TOOLCHAIN/bin/$TARGET${API_LEVEL}-clang
    export AS=$CC
    export CXX=$TOOLCHAIN/bin/$TARGET${API_LEVEL}-clang++
    export LD=$TOOLCHAIN/bin/ld
    export RANLIB=$TOOLCHAIN/bin/llvm-ranlib
    export STRIP=$TOOLCHAIN/bin/llvm-strip

    CXX_STL="-lc++_shared"
  fi

  # Set *FLAGS for the build, once again, configure reads these from
  # the environment.
  export CPPFLAGS="${CPPFLAGS} -fPIC -I${OPENSSL_NDK_DIST}/include"
  export CXXFLAGS="${CXXFLAGS} -Os"
  export LDFLAGS="${LDFLAGS} -L${OPENSSL_NDK_DIST} ${CXX_STL}"

  autoreconf -fi

  # To make the paths shorter, we simply install to /libs
  # Inside the Android APK package file they will be in
  # the /lib directory.
  # To compile other parts of the reSIProcate stack, add
  # them to this configure command, for example, --with-repro
  ./configure \
    --libdir=/libs/${MOD_NAME} \
    --host=${CROSS_COMPILE} \
    --with-sysroot=${SYSROOT} \
    --enable-android \
    --with-ssl \
    "$@"

  # these need asio and boost headers
  # reTurn can be modified to use C++11 std::bind and friends to
  # reduce dependency on boost
  # --with-return --with-recon

  # We build the specified directories one by one.
  for proj in $PROJECTS ;
  do
    # We clean any leftovers from another architecture that
    # was built in a previous modulation.
    make -C $proj clean
    # Compile and install to the staging directory in one step.
    make -C $proj -j${PAR} DESTDIR=${STAGE_PREBUILT} install
  done

  # Run the unit tests
  #for proj in $PROJECTS ;
  #do
  #  make -C $proj -i -j$PAR check
  #done

  echo "Removing temporary toolchain ${MY_NDK} ..."
  rm -rf "${MY_NDK}"

done

# After completing the build for every architecture, copy
# both the libraries and Android.mk into the ${PROJECT_DIST}
# where they can be used by the SDK when building apps.
echo "Copying libs into place ..."
mkdir -p ${PROJECT_DIST}
cp -r ${STAGE_PREBUILT}/libs/* ${PROJECT_DIST}
cp build/android/prebuilt/Android.mk ${PROJECT_DIST}
rm -rf "${STAGE_PREBUILT}"

echo "All done"

