#!/bin/bash

: <<'END_COMMENT'
    This script retains only those functions from the original compute_utils.sh
    that the ROCm build scripts utilize.
END_COMMENT

set -e
set -o pipefail


# Set a sensible default value for DASH_JAY in case none is provided
DASH_JAY=${DASH_JAY:-"-j $(nproc)"}

# Enable ccache by default unless requested otherwhise
if [[ "$ROCM_USE_CCACHE" != "0" ]] ; then
	for d in /usr/lib/ccache /usr/lib64/ccache ;do
		if [ -d "$d" ]; then
			PATH="$d:$PATH"
			break # Only add one ccache at most
		fi
	done
fi

# Print message to stderr
#   param message string to print on exit
# Example: printErr "file not found"
printErr() {
    echo "$@" 1>&2
}

# Print message to stderr and terminate current program
#   param message string to print on exit
# Example: die "Your program" has terminated
die() {
    printErr "FATAL: $@"
    exit 1
}

# Die if first argument is empty
#   param string to validate
#   param error message
# Example: die "$VARIABLE" "Your program" has terminated
dieIfEmpty() {
    if [ "$1" == "" ]; then
        shift
        die "$@"
    fi
}

# Get directory with build output package
# Precedence:
#       1. PWD
#       2. Caller's folder
#       3. Known build output folder
getPackageRoot() {
    local scriptPath=$(readlink -f $(dirname $BASH_SOURCE))
    local testFile="build.version"

    if [ -a "$PWD/$testFile" ]; then
        echo "$PWD"
    elif [ -a "$scriptPath/../$testFile" ]; then
        echo "$scriptPath/.."
    elif [ -a "$scriptPath/$testFile" ]; then
        echo "$scriptPath"
    elif [ ! -z "$OUT_DIR" ]; then
        echo "$OUT_DIR"
    else
        die "Failed to determine package directory"
    fi
}

# Get a list of directories containing the build output
# shared objects.
# Important: PWD takes precedence over build output folder
getLibPath() {
    local packageRoot="$(getPackageRoot)"
    dieIfEmpty "$packageRoot"
    echo "$packageRoot/lib"
}

# Get a list of directories containing the output executables
#     param binDir (optional) - package name
# Important: PWD takes precedence over build output folder
getBinPath() {
    local binDir="$1"
    local packageRoot=$(getPackageRoot)
    dieIfEmpty "$packageRoot"

    if [ "$binDir" == "" ]; then
        echo "$packageRoot/bin"
    else
        echo "$packageRoot/bin/$binDir"
    fi
}

# Get a list of directories containing the output source files
# Important: PWD takes precedence over build output folder
getSrcPath() {
    local packageRoot=$(getPackageRoot)
    dieIfEmpty "$packageRoot"
    echo "$packageRoot/src"
}

# Get a list of directories to place build output
#   param moduleName - name of the module for the build path
# Important: PWD takes precedence over build output folder
getBuildPath() {
    local moduleName="$1"
    local packageRoot=$(getPackageRoot)
    dieIfEmpty "$packageRoot"
    echo "$packageRoot/build/$moduleName"
}

# Get a list of directories containing the output etc files
# Important: PWD takes precedence over build output folder
getUtilsPath() {
    local packageRoot=$(getPackageRoot)
    dieIfEmpty "$packageRoot"
    echo "$packageRoot/utils"
}

# Get a list of directories containing the output include files
# Important: PWD takes precedence over build output folder
getIncludePath() {
    local packageRoot=$(getPackageRoot)
    dieIfEmpty "$packageRoot"
    echo "$packageRoot/include"
}

# Get the directory containing the cmake config files
getCmakePath() {
    local rocmInstallPath=${ROCM_INSTALL_PATH}
    local cmakePath="lib/cmake"
    if [ "$ASAN_CMAKE_PARAMS" == "true" ] ; then
        cmakePath="lib/asan/cmake"
    fi
    dieIfEmpty "$rocmInstallPath"
    echo "$rocmInstallPath/$cmakePath"
}

# Get a list of directories containing the output debian files
# Important: PWD takes precedence over build output folder
getDebPath() {
    local packageName="$1"
    dieIfEmpty "$packageName" "No valid package name specified"

    local packageRoot=$(getPackageRoot)
    dieIfEmpty "$packageRoot"

    echo "$packageRoot/deb/$packageName"
}

# Get a list of directories containing the output rpm files
# Important: PWD takes precedence over build output folder
getRpmPath() {
    local packageName="$1"
    dieIfEmpty "$packageName" "No valid package name specified"

    local packageRoot=$(getPackageRoot)
    dieIfEmpty "$packageRoot"

    echo "$packageRoot/rpm/$packageName"
}



verifyEnvSetup() {
    if [ -z "$OUT_DIR" ]; then
        die "Please source build/envsetup.sh first."
    fi
}

# Copy a file or directory to target location and show single line progress
progressCopy() {
    if [ -d "$1" ]; then
        rsync -a "$1"/* "$2"
    else
        rsync -a "$1" "$2"
    fi
}


#following three common functions have been written to addition of static libraries
print_lib_type() {
   if [ "$1" == "OFF" ];
   then
       echo " Building Archive "
   else
       echo " Building Shared Object "
   fi
}

check_conflicting_options() {
    # 1->CLEAN_OR_OUT 2->PKGTYPE 3->MAKETARGET
    RET_CONFLICT=0
    if [ $1 -ge 2 ]; then
       if [ "$2" != "deb" ] && [ "$2" != "rpm" ] && [ "$2" != "tar" ]; then
          echo " Wrong Param Passed for Package Type for the Outdir... "
          RET_CONFLICT=30
       fi
    fi
    # check Clean Vs Outdir
    if [ $1 -ge 3 ] && [ $RET_CONFLICT -eq 0 ] ; then
       echo " Clean & Out Both are sepcified.  Not accepted. Bailing .. "
       RET_CONFLICT=40
    fi
    if [ $RET_CONFLICT -eq 0 ] && [ "$3" != "deb" ] && [ "$3" != "rpm" ] && [ "$3" != "all" ] && [ "$3" != "tar" ]; then
       echo " Wrong Param Passed for Package Type... "
       RET_CONFLICT=50
    fi
}

set_asan_env_vars() {
    # Flag to set cmake build params for ASAN builds
    ASAN_CMAKE_PARAMS="true"
    # Pass the LLVM bin path as the first parameter
    LLVM_BIN_DIR=${1:-"${ROCM_INSTALL_PATH}/llvm/bin"}
    export CC="$LLVM_BIN_DIR/clang"
    export CXX="$LLVM_BIN_DIR/clang++"
    export PATH="$PATH:$LLVM_BIN_DIR/"
    # get exact path to ASAN lib containing clang version
    ASAN_LIB_PATH=$(clang --print-file-name=libclang_rt.asan-x86_64.so)
    export LD_LIBRARY_PATH="${ASAN_LIB_PATH%/*}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
    export ASAN_OPTIONS="detect_leaks=0"
}

set_address_sanitizer_on() {
    # In SLES and RHEL debuginfo package is not getting generated
    # when compiler is set to clang. Using default -gdwarf-5 is getting unhandled in these distros
    # So setting -gdwarf-4 as a quick fix
    # TODO: -gdwarf-5 unhandling when compiler set to clang need to be fixed
    SET_DWARF_VERSION_4=""
    if [[ $DISTRO_ID == sles* ]] || [[ $DISTRO_ID == rhel* ]]; then
        SET_DWARF_VERSION_4="-gdwarf-4"
    fi
    export CFLAGS="-fsanitize=address -shared-libasan -g $SET_DWARF_VERSION_4"
    export CXXFLAGS="-fsanitize=address -shared-libasan -g $SET_DWARF_VERSION_4"
    export LDFLAGS="-Wl,--enable-new-dtags -fuse-ld=lld  -fsanitize=address -shared-libasan -g -Wl,--build-id=sha1 -L$ROCM_INSTALL_PATH/lib/asan"
}

ack_and_ignore_asan() {
    echo "-a parameter accepted but ignored"
}

#debug function #dumping values in case of error to solve the same
print_vars() {
echo " Status of Vars in $1 build "
echo " TARGET= $2 "
echo " BUILD_TYPE = $3 "
echo " SHARED_LIBS = $4 "
echo " CLEAN_OR_OUT = $5 "
echo " PKGTYPE= $6 "
echo " MAKETARGET = $7 "
}

# Provide this as a function, rather than a variable to delay the evaluation
# of variables. In particular we might want to put code in here which changes
# depending on if we are building with the address sanitizer or not
# Can do things like set the packaging type - no point in packaging RPM on debian and
# vica versa.
# Set CPACK_RPM_INSTALL_WITH_EXEC so it packages debug info for shared libraries.
rocm_common_cmake_params(){
    if [ "$BUILD_TYPE" = "RelWithDebInfo" ] ; then
	printf '%s ' "-DCPACK_RPM_DEBUGINFO_PACKAGE=TRUE" \
	       "-DCPACK_DEBIAN_DEBUGINFO_PACKAGE=TRUE" \
	       "-DCPACK_RPM_INSTALL_WITH_EXEC=TRUE" \
               # end of list comment or blank line
    fi
    printf '%s ' "-DROCM_DEP_ROCMCORE=ON" \
                 "-DCMAKE_EXE_LINKER_FLAGS_INIT=-Wl,--enable-new-dtags,--build-id=sha1,--rpath,$ROCM_EXE_RPATH" \
                 "-DCMAKE_SHARED_LINKER_FLAGS_INIT=-Wl,--enable-new-dtags,--build-id=sha1,--rpath,$ROCM_LIB_RPATH" \
                 "-DFILE_REORG_BACKWARD_COMPATIBILITY=OFF" \
                 "-DINCLUDE_PATH_COMPATIBILITY=OFF" \
    # set lib directory to lib/asan for ASAN builds
    # Disable file reorg backward compatibilty for ASAN builds
    # ENABLE_ASAN_PACKAGING - Used for enabling ASAN packaging
    if [ "$ASAN_CMAKE_PARAMS" == "true" ] ; then
        local asan_common_cmake_params
        local ASAN_LIBDIR="lib/asan"
        local CMAKE_PATH=$(getCmakePath)
        asan_common_cmake_params=(
            "-DCMAKE_INSTALL_LIBDIR=$ASAN_LIBDIR"
            "-DCMAKE_PREFIX_PATH=$CMAKE_PATH;${ROCM_INSTALL_PATH}/$ASAN_LIBDIR;$ROCM_INSTALL_PATH/llvm;$ROCM_INSTALL_PATH"
            "-DENABLE_ASAN_PACKAGING=$ASAN_CMAKE_PARAMS"
            "-DCMAKE_SHARED_LINKER_FLAGS_INIT=-Wl,--enable-new-dtags,--build-id=sha1,--rpath,$ROCM_ASAN_LIB_RPATH"
        )
        printf '%s ' "${asan_common_cmake_params[@]}"
    else
        printf '%s ' "-DCMAKE_INSTALL_LIBDIR=lib" \
        # end of list comment or blank line
    fi
}

rocm_cmake_params() {
    local cmake_params

    cmake_params=(
        "-DCMAKE_PREFIX_PATH=${ROCM_INSTALL_PATH}/llvm;${ROCM_INSTALL_PATH}"
        "-DCMAKE_BUILD_TYPE=${BUILD_TYPE:-'RelWithDebInfo'}"
        "-DCMAKE_VERBOSE_MAKEFILE=1"
        "-DCPACK_GENERATOR=${CPACKGEN:-'DEB;RPM'}"
        "-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=FALSE"
        "-DROCM_PATCH_VERSION=${ROCM_LIBPATCH_VERSION}"
        "-DCMAKE_INSTALL_PREFIX=${ROCM_INSTALL_PATH}"
        "-DCPACK_PACKAGING_INSTALL_PREFIX=${ROCM_INSTALL_PATH}"
    )

    printf '%s ' "${cmake_params[@]}"
}

copy_if(){
    local type=$1 selector=$2 dir=$3
    shift 3
    mkdir -p "$dir"
    if [[ "$selector" =~ "$type" ]] ; then
	cp -a "$@" "$dir"
    fi
    # handle ddeb files as well, renaming them on the way
    for f
    do
	case "$f" in
	    # Properly formed debian package name is a number of _ separated fields
	    # The first is the package name.
	    # Second is version number
	    # third is architecture
	    # Ensure we have at least one _ in the name
	    (*"_"*".deb")
		local deb=${f%.deb}
		local basename=${deb##*/}
		local dirname=${f%/*}
                # filename($f) can be either /some/path/pkgname.deb or pkgname.deb
                # If its pkgname.deb, then directory should be .
                [[ "$dirname" == "$f" ]] && dirname=.
		local pkgname=${basename%%_*}
		local pkgextra=${basename#*_}
		# cmake 3.22 creates the filename by replacing .deb with -dbgsym.ddeb
		# at least for hostcall. Mind you hostcall looks to be incorrectly packaged.
		if [ -e "${deb}-dbgsym.ddeb" ]
		then
		    dest=${deb##*/}
		    dest="${dest%%_*}-dbgsym_${dest#*_}"
		    cp -a "${deb}-dbgsym.ddeb" "$dir/${dest##*/}.deb"
		fi
		# This is needed for comgr
		if [ -e "$dirname/${pkgname}-dbgsym_${pkgextra}.ddeb" ]
		then
		    cp "$dirname/${pkgname}-dbgsym_${pkgextra}.ddeb" "$dir/${pkgname}-dbgsym_${pkgextra}.deb"
		fi
		;;
	esac
    done
}


# Function to remove -r or -R from MAKEFLAGS
remove_make_r_flags(){
    local firstword='^[^ ]*'
    if [[ "$MAKEFLAGS" =~ ${firstword}r ]] ; then MAKEFLAGS=${MAKEFLAGS/r/} ; fi
    if [[ "$MAKEFLAGS" =~ ${firstword}R ]] ; then MAKEFLAGS=${MAKEFLAGS/R/} ; fi
}

# Set a variable to the value needed by cmake to use ninja if it is available
# If GEN_NINJA is already defined, even as the empty string, then leave the value alone
# Intended use in build_xxxx.sh is ${GEN_NINJA:+"$GEN_NINJA"} to cope with potentially weird values
# but in practice just ${GEN_NINJA} without quotes will be fine.
# e.g.            cmake -DCMAKE_BUILD_TYPE="$BUILD_TYPE" $GEN_NINJA
# If for some reason you wanted to build without ninja just export an empty GEN_NINJA variable
if [ "${GEN_NINJA+defined}" != "defined" ] && command -v ninja >/dev/null ; then
    GEN_NINJA=-GNinja
fi

