#!/bin/bash
#
#  aomp_common_vars: This file is sourced by all AOMP build scripts.
#
#     This file is stored in aomp/bin directory of the aomp repo.
#     You don't need to change this file unless you want to change
#     default values for all AOMP developers. To customize your build,
#     set environment variables defined in this file.
#
#     The bash syntax ENVNAME=${ENVNAME:-value} checks if ENVNAME is
#     already set. If not, it assigns it the value following the :-

# The AOMP_COMPILER_NAME is used whenever version is queried.
# FIXME: More work is needed to propogate the use of AOMP_COMPILER_NAME.
AOMP_COMPILER_NAME=${AOMP_COMPILER_NAME:-AOMP}

# ROCM_VERSION may be set by Jenkins, if not guess a good number
ROCM_VERSION=${ROCM_VERSION:-3.5.0}

# Set the AOMP VERSION STRING and AOMP_PROJECT_REPO_BRANCH.
AOMP_VERSION=${AOMP_VERSION:-"11.5"}
AOMP_VERSION_MOD=${AOMP_VERSION_MOD:-"1"}
AOMP_VERSION_STRING=${AOMP_VERSION_STRING:-"$AOMP_VERSION-$AOMP_VERSION_MOD"}
export AOMP_VERSION_STRING AOMP_VERSION AOMP_VERSION_MOD ROCM_VERSION

# Set install directory and the link directory.
# AOMP will be a symbolic link AOMP_INSTALL_DIR is the versioned dir name
AOMP=${AOMP:-$HOME/rocm/aomp}
AOMP_INSTALL_DIR=${AOMP}_${AOMP_VERSION_STRING}

# Set the directory location where all local AOMP git repos are stored.
# For example, if AOMP_REPOS=$HOME/git/aomp11, then the primary aomp repo
# is stored in $HOME/git/aomp11/aomp and the mono repo is stored in
# $HOME/aomp/llvm-project.
AOMP_REPOS=${AOMP_REPOS:-$HOME/git/aomp11}

# Because the source for all repos are tarred for release, we store
# all the test repositories in a different directory.
AOMP_REPOS_TEST=${AOMP_REPOS_TEST:-$HOME/git/aomp-test}

# To build aomp from the release source taball, set these values to 0
AOMP_CHECK_GIT_BRANCH=${AOMP_CHECK_GIT_BRANCH:-1}
AOMP_APPLY_ROCM_PATCHES=${AOMP_APPLY_ROCM_PATCHES:-1}

#Set common rpath for build scripts
AOMP_ORIGIN_RPATH="-DCMAKE_SHARED_LINKER_FLAGS='-Wl,--disable-new-dtags' -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON -DCMAKE_INSTALL_RPATH=\$ORIGIN:\$ORIGIN/../lib:\$ORIGIN/../hsa/lib:\$ORIGIN/../../lib64:\$ORIGIN/../../hsa/lib:$AOMP_INSTALL_DIR/lib:$AOMP_INSTALL_DIR/hsa/lib"

CUDA=${CUDA:-/usr/local/cuda}
CUDAT=${CUDAT:-$CUDA/targets}
CUDAINCLUDE=${CUDAINCLUDE:-$CUDA/include}
CUDABIN=${CUDABIN:-$CUDA/bin}

AOMP_CMAKE=${AOMP_CMAKE:-cmake}
AOMP_PROC=`uname -p`
if [ "$AOMP_PROC" == "unknown" ] ; then
   AOMP_PROC=`uname -a | awk '{print $(NF-1)}'`
fi

GCC=`which gcc`
GCCXX=`which g++`
AOMP_CC_COMPILER=${AOMP_CC_COMPILER:-$GCC}
AOMP_CXX_COMPILER=${AOMP_CXX_COMPILER:-$GCCXX}

# Non standalone builds are done with ROCm builds.
AOMP_STANDALONE_BUILD=${AOMP_STANDALONE_BUILD:-1}

#  The logic for turning on CUDA build is here
if [ $AOMP_STANDALONE_BUILD == 1 ] ; then
   # Default is to build nvptx for STANDALONE build
   AOMP_BUILD_CUDA=${AOMP_BUILD_CUDA:-1}
else
   # Default is to NOT build nvptx for ROCm integrated build
   AOMP_BUILD_CUDA=${AOMP_BUILD_CUDA:-0}
fi
# Regardless, turn off AOMP_BUILD_CUDA if CUDA not available
if [ ! -d "$CUDABIN" ] ; then
   AOMP_BUILD_CUDA=0
fi
# Regardless, turn off AOMP_BUILD_CUDA for arm
if [ "$AOMP_PROC" == "aarch64" ] ; then
   AOMP_BUILD_CUDA=0
fi

# Set list of default nvptx subarchitectures to build
# Only Cuda 9 and above supports sm_70
if [ "$AOMP_BUILD_CUDA" == 1 ] ; then
   NVPTXGPUS_DEFAULT="30,32,35,50,60,61"
   if [ -f $CUDA/version.txt ] ; then
      if [ `head -1 /usr/local/cuda/version.txt | cut -d " " -f 3 | cut -d "." -f 1` -ge 9 ] ; then
         NVPTXGPUS_DEFAULT+=",70"
      fi
   fi
   #  Developers should override NVPTXGPUS to shorten build time.
   NVPTXGPUS=${NVPTXGPUS:-"${NVPTXGPUS_DEFAULT}"}
   AOMP_NVPTX_TARGET="NVPTX;"
else
   NVPTXGPUS_DEFAULT=""
   NVPTXGPUS=""
   AOMP_NVPTX_TARGET=""
fi

# Set list of default amdgcn subarchitectures to build
# Developers may override GFXLIST to shorten build time.
GFXLIST=${GFXLIST:-"gfx700 gfx701 gfx801 gfx803 gfx900 gfx902 gfx906 gfx908 gfx90a gfx1030 gfx1031"}
export GFXLIST

# Calculate the number of threads to use for make
NUM_THREADS=
if [ ! -z `which "getconf"` ]; then
   NUM_THREADS=$(`which "getconf"` _NPROCESSORS_ONLN)
   if [ "$AOMP_PROC" == "ppc64le" ] ; then
      NUM_THREADS=8
   fi
   if [ "$AOMP_PROC" == "aarch64" ] ; then
      NUM_THREADS=$(( NUM_THREADS / 4))
   fi
fi

# These are the web sites where the AOMP git repos are pulled from
GITROC="https://github.com/radeonopencompute"
GITROCDEV="https://github.com/ROCm-Developer-Tools"
GITROCLIB="https://github.com/AMDComputeLibraries"
GITKHRONOS="https://github.com/KhronosGroup"

# FIXME: In the near future, we will remove the _BRANCH variables and use a
#        manifest file to determine which branch to build each component.
#
# The difference between a _REPO_NAME and _REPO_GITNAME is that the
# _REPO_NAME is the directory name following $AOMP_REPOS.  The GITNAME
# Is the name of the git repository used in the clone_aomp script.
# The _REPO_GITNAME variables will also be removed with the conversion to
# the use of the repo tool.

# External component names for LLVM_EXTERNAL_PROJECTS may have no special
# characters in them.  Therefore, AOMP_xxx_REPO_NAME is different than
# AOMP_xxx_COMPONENT NAME for some components. Recommend that component
# names be short lowercase names.

#  These aomp development repositories
AOMP_REPO_NAME=${AOMP_REPO_NAME:-aomp}
AOMP_REPO_BRANCH=${AOMP_REPO_BRANCH:-amd-stg-openmp}
AOMP_PROJECT_REPO_NAME=${AOMP_PROJECT_REPO_NAME:-amd-llvm-project}
AOMP_PROJECT_REPO_BRANCH=${AOMP_PROJECT_REPO_BRANCH:-amd-stg-openmp}
AOMP_EXTRAS_REPO_NAME=${AOMP_EXTRAS_REPO_NAME:-aomp-extras}
AOMP_EXTRAS_REPO_BRANCH=${AOMP_EXTRAS_REPO_BRANCH:-amd-stg-openmp}
AOMP_FLANG_REPO_NAME=${AOMP_FLANG_REPO_NAME:-flang}
AOMP_FLANG_REPO_BRANCH=${AOMP_FLANG_REPO_BRANCH:-amd-stg-openmp}

#  These extra repositories are needed but we cannot update them
AOMP_ROCT_REPO_NAME=${AOMP_ROCT_REPO_NAME:-roct-thunk-interface}
AOMP_ROCT_REPO_BRANCH=${AOMP_ROCT_REPO_BRANCH:-roc-3.3.x}
AOMP_ROCT_COMPONENT_NAME=${AOMP_ROCT_COMPONENT_NAME:-roct}
AOMP_ROCR_REPO_NAME=${AOMP_ROCR_REPO_NAME:-rocr-runtime}
AOMP_ROCR_REPO_BRANCH=${AOMP_ROCR_REPO_BRANCH:-rocm-3.3.x}
AOMP_ROCR_COMPONENT_NAME=${AOMP_ROCR_COMPONENT_NAME:-rocr}
AOMP_LIBDEVICE_REPO_NAME=${AOMP_LIBDEVICE_REPO_NAME:-rocm-device-libs}
AOMP_LIBDEVICE_COMPONENT_NAME=${AOMP_LIBDEVICE_COMPONENT_NAME:-rocdl}
AOMP_LIBDEVICE_REPO_BRANCH=${AOMP_LIBDEVICE_REPO_BRANCH:-amd-stg-open}
AOMP_LIBDEVICE_REPO_SHA=${AOMP_LIBDEVICE_REPO_SHA:-168cbba7c}
AOMP_COMGR_REPO_NAME=${AOMP_COMGR_REPO_NAME:-rocm-compilersupport}
AOMP_COMGR_REPO_BRANCH=${AOMP_COMGR_REPO_BRANCH:-amd-stg-open}
AOMP_COMGR_REPO_SHA=${AOMP_COMGR_REPO_SHA:-9b0cdb6}
AOMP_RINFO_REPO_NAME=${AOMP_RINFO_REPO_NAME:-rocminfo}
AOMP_RINFO_REPO_BRANCH=${AOMP_RINFO_REPO_BRANCH:-master}
AOMP_RINFO_REPO_SHA=${AOMP_RINFO_REPO_SHA:-1a81ee3}

# These are repos we will use when we switch to HIP VDI
AOMP_VDI_REPO_NAME=${AOMP_VDI_REPO_NAME:-vdi}
AOMP_VDI_REPO_BRANCH=${AOMP_VDI_REPO_BRANCH:-master}
AOMP_VDI_REPO_GITNAME=${AOMP_VDI_REPO_GITNAME:-ROCclr}
AOMP_OCL_REPO_NAME=${AOMP_OCL_REPO_NAME:-opencl-on-vdi}
AOMP_OCL_REPO_GITNAME=${AOMP_OCL_REPO_GITNAME:-ROCm-OpenCL-Runtime}
AOMP_OCL_REPO_BRANCH=${AOMP_OCL_REPO_BRANCH:-master-next}
AOMP_HIPVDI_REPO_NAME=${AOMP_HIPVDI_REPO_NAME:-hip-on-vdi}
AOMP_HIPVDI_REPO_GITNAME=${AOMP_HIPVDI_REPO_GITNAME:-hip}
AOMP_HIPVDI_REPO_BRANCH=${AOMP_HIPVDI_REPO_BRANCH:-master-next}

# These are test repositories
GITNEKBONE="https://github.com/AMDComputeLibraries"
AOMP_NEKBONE_REPO_NAME=${AOMP_NEKBONE_REPO_NAME:-Nekbone}
AOMP_NEKBONE_REPO_BRANCH=${AOMP_NEKBONE_REPO_BRANCH:-amd-openmp}
AOMP_APPS_REPO_NAME=${AOMP_APPS_REPO_NAME:-openmpapps}
GITSOLVV="https://github.com/SOLLVE"
AOMP_SOLVV_REPO_NAME=${AOMP_SOLVV_REPO_NAME:-sollve_vv}
AOMP_SOLVV_REPO_BRANCH=${AOMP_SOLVV_REPO_BRANCH:-master}
AOMP_APPS_REPO_NAME=${AOMP_APPS_REPO_NAME:-openmpapps}
AOMP_APPS_REPO_BRANCH=${AOMP_APPS_REPO_BRANCH:-AOMP-0.5}
GITLLNL="https://github.com/llnl"
AOMP_RAJA_REPO_NAME=${AOMP_RAJA_REPO_NAME:-raja}
AOMP_RAJA_REPO_BRANCH=${AOMP_RAJA_REPO_BRANCH:-master}
AOMP_INTERNAL_IP="gitlab1.amd.com"
GITINTERNAL="http://${AOMP_INTERNAL_IP}/dmcdouga"  # This will change soon

#  We dont use this yet, waiting for trunk merge
AOMP_F18_REPO_NAME=${AOMP_F18_REPO_NAME:-f18}
AOMP_F18_REPO_BRANCH=${AOMP_F18_REPO_BRANCH:-master}

AOMP_PATCH_CONTROL_FILE=${AOMP_PATCH_CONTROL_FILE:-${AOMP_REPOS}/${AOMP_REPO_NAME}/bin/patches/patch-control-file.txt}

STASH_BEFORE_PULL=${STASH_BEFORE_PULL:-YES}

# It is highly recommendded that developers set SUDO to disable and 
# this have update access to install directory $AOMP. In the future
# we may set this default to disable 
SUDO=${SUDO:-NO}
if [ "$SUDO" == "set" ]  || [ "$SUDO" == "yes" ] || [ "$SUDO" == "YES" ] ; then
   SUDO="sudo"
else
   SUDO=""
fi

# The default for BUILD_AOMP is AOMP_REPOS. 
# The cmake and make builds are actually done in 
# BUILD_AOMP/build, not the actual repos. 
BUILD_AOMP=${BUILD_AOMP:-$AOMP_REPOS}
BUILD_DIR=$BUILD_AOMP

# If you override BUILD_AOMP to something other than AOMP_REPOS
# then the scripts will copy the repository sources from AOMP_REPOS
# to the directory BUILD_AOMP. A developer would do this for a
# couple of reasons.  1) access to git repos is slow and 
# access to BUILD_AOMP is fast or 2) lots of updates and test code
# is planned that are not desired in his git repository. 
# This COPYSOURCE flag is used by build scripts to conditianlly rsync
# source code to the BUILD_AOMP/build/<component>  directory.
if [ "$BUILD_DIR" != "$AOMP_REPOS" ] ; then
   COPYSOURCE=true
fi

# Here is where we define different behaviors for STANDALONE build
# and the new ROCm integrated build. The default is STANDALONE build.
if [ $AOMP_STANDALONE_BUILD == 1 ] ; then
   # Standalone build gets ROCm components from the AOMP Installation.
   # As a result their is an order to component builds.
   ROCM_DIR=${ROCM_DIR:-$AOMP_INSTALL_DIR}
   # We hardcode the ROCM_VERSION here for standalone builds
else
   # ROCm integrated build gets ROCm pieces from installed ROCm
   ROCM_DIR=${ROCM_DIR:-/opt/rocm}
   # Jenkins builds may not use the current development branches.
   # So we turn off git branch checking.
   AOMP_CHECK_GIT_BRANCH=0
   # Jenkins build will set the build directory BUILD_DIR to its own work area.
   # And since that is not $AOMP_REPOS/build COPYSOURCE will be turned on above.
   # We dont want that.  So for now, turn it off for ROCm integrated builds.
   unset COPYSOURCE

   # For Integrated ROCm build we do not install to versioned dir and create 
   # a symbolic link.  Instead we install directly to /opt/rocm/aomp
   AOMP_INSTALL_DIR=${AOMP}
fi

#  Check the repositories exist and are on the correct branch
function checkrepo(){
   if [ ! -d $REPO_DIR ] ; then
      echo "ERROR:  Missing repository directory $REPO_DIR"
      exit 1
   fi
   if [ "$AOMP_CHECK_GIT_BRANCH" == 1 ] ; then
      cd $REPO_DIR
      COBRANCH=`git branch --list | grep "\*" | cut -d" " -f2`
      if [ "$COBRANCH" != "$REPO_BRANCH" ] ; then
         if [ "$COBRANCH" == "master" ] ; then
           echo "EXIT:  Repository $REPO_DIR is on development branch: master"
           exit 1
	 elif [ "$COBRANCH" == "(HEAD" ] ; then
           echo "we have an override $REPO_DIR"
         else
           echo "ERROR:  The repository at $REPO_DIR is not on branch $REPO_BRANCH"
           echo "          It is on branch $COBRANCH"
           exit 1
        fi
      fi
   fi
}

#  TO use this function set variables patchdir and patchfile
function patchrepo(){
patchdir=$1
if [ "$AOMP_APPLY_ROCM_PATCHES" == 1 ] && [ -d "$patchdir" ] ; then
   patches=""
   cd $patchdir
   if [[ "$2" =~ "postinstall" ]]; then
     getpatchlist $2
   else
     getpatchlist
   fi

   #loop through list of patches to apply
   if [ "$patches" != "" ] ; then
   patchloc=${AOMP_PATCH_CONTROL_FILE%/*}
   echo patchloc=$patchloc
   for patch in $patches; do
     patchfile=$patchloc/$patch
     echo "Testing patch $patchfile to $patchdir"

     applypatch="yes"
     patch -p1 -t -N --dry-run <$patchfile >/dev/null
     if [ $? != 0 ] ; then
        applypatch="no"
        # Check to see if reverse patch applies cleanly
        patch -p1 -R --dry-run -t <$patchfile >/dev/null
        if [ $? == 0 ] ; then
           echo "patch $patchfile was already applied to $patchdir"
        else
           echo
           echo "ERROR: Patch $patchfile will not apply"
           echo "       cleanly to directory $patchdir"
           echo "       Check if it was already applied."
           echo
           exit 1
        fi
     fi
     if [ "$applypatch" == "yes" ] ; then
        echo "Applying patch $patchfile to $patchdir"
        patch -p1 --no-backup-if-mismatch <$patchfile
     fi
   done
   fi
fi

}

function removepatch(){
patchdir=$1
if [ "$AOMP_APPLY_ROCM_PATCHES" == 1 ] && [ -d "$patchdir" ] ; then
   patches=""
   cd $patchdir
   getpatchlist
   if [ "$patches" != "" ] ; then
      echo "Patchdir $patchdir"
      echo "PATCHES TO REMOVE: $patches"
   fi
   patchloc=${AOMP_PATCH_CONTROL_FILE%/*}
   if [ "$patches" != "" ] ; then
   for patch in $patches; do
     patchfile=$patchloc/$patch
     echo "Testing reverse patch $patchfile to $patchdir"
     reversepatch="yes"
     # Check to see if reverse patch applies cleanly
     patch -p1 -R --dry-run -f <$patchfile  >/dev/null
     if [ $? != 0 ] ; then
        echo "patch $patchfile was NOT applied $patchdir, no patch to reverse"
        reversepatch="no"
     fi
     if [ "$reversepatch" == "yes" ] ; then
        echo "Reversing patch $patchfile to $patchdir"
        patch -p1 -R -f --no-backup-if-mismatch <$patchfile
     fi
   done
   fi
fi
}

function getpatchlist(){
   currdir=$(pwd)
   basedir=$(basename $currdir)
   if [[ "$1" =~ "postinstall" ]]; then
     reporegex="(^$1:\s)"
   else
     reporegex="(^$basedir:\s)"
   fi
   #read patch control file and look for correct patches
   while read -r line; do
   if [[ "$line" =~ $reporegex ]]; then
     #remove basename from list of patches
     patches=${line/"${BASH_REMATCH[1]}"}
     echo "patches: $patches"
     break
   fi
   done < "$AOMP_PATCH_CONTROL_FILE"
}

function help_build_aomp(){
   /bin/cat 2>&1 <<"EOF"

  The build scripts in this directory are used to build AOMP.
  
  Repositories:
     Many repositories are used to build AOMP.  The script clone_aomp.sh will
     clone all the necessary repositories as subdirectories of the directory
     $HOME/git/aomp11. The web repository locations and the required branches
     are set with the file aomp_common_vars
  
  Build all components:
     To build all components, run these commands:

        ./clone_aomp.sh
        unset LD_LIBRARY_PATH
        ./build_aomp.sh

  Component builds:
     Developers can rebuild individual components by running the build script for
     that component. Make sure dependent components are built first. You can run
     build_aomp.sh to build call components in the correct order orsee the README.md
     file in this directory for the required order.

     Each build script can run with no arguments or with a single argument
     "install" or "nocmake".  Running  with no options starts fresh with an empty
     component build directory.  It then runs cmake with the correct cmake options
     then it runs make with a proper -j option.
  
  Optional Arguments 'nocmake' and 'install' :
     The 'nocmake' or 'install' options can only be used after your initial build
     with no options. The 'nocmake' option is intended to restart make after 
     you fix code following a failed build. The 'install' option will run 'make' 
     and 'make install' causing installation into the directory $AOMP_INSTALL_DIR. 
     The 'install' option will also create a symbolic link to directory $AOMP.
  
  Environment Variables:
     You can set environment variables to override behavior of the build scripts
     NAME             DEFAULT             DESCRIPTION
     ----             -------             -----------
     AOMP             $HOME/rocm/aomp     Where the compiler will be installed
     AOMP_REPOS       $HOME/git/aomp11    Location of all aomp repos
     BUILD_TYPE       Release             The CMAKE build type
     BUILD_AOMP       same as AOMP_REPOS  Set a different build location than AOMP_REPOS
  
  To build a debug version of the compiler, run this command before the build:
     export BUILD_TYPE=debug
  
  The BUILD_AOMP Envronment Variable:
     The build scripts will always build with cmake and make outside your source git trees.
     By default (without BUILD_AOMP) the build will occur in the "build" subdirectory of
     AOMP_REPOS. For example build_llvm will build in $AOMP_REPOS/build/llvm
  
     The BUILD_AOMP environment variable enables source development outside your git
     repositories. By default, this feature is OFF.  The BUILD_AOMP environment variable 
     can be used if access to your git repositories is very slow or you want to test 
     changes outside of your local git repositories (specified by AOMP_REPOS env var). 
     If BUILD_AOMP is set, your git repositories (specifed by AOMP_REPOS) will be
     replicated to subdirectories of BUILD_AOMP using rsync.  The subsequent build 
     (cmake and make) will occur in subdirectory BUILD_AOMP/build/llvm.
     This replication only happens on your initial build, that is, if you specify no arguments.
     The option 'nocmake' skips replication and then restarts make in the build directory.
     The install option skips replication, skips cmake, runs 'make' and 'make install'. 
     Be careful to always use options nocmake or install if you made local changes in
     BUILD_AOMP or your changes will be lost by a new replica of your git repositories.
  
EOF
   exit 0
}
