#!/bin/bash

#File:install.sh

#===----------------------------------------------------------------------===#
#==== Copyright (c) 2015 Advanced Micro Devices, Inc. All rights reserved.
#
# Developed by: Advanced Micro Devices, Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# with the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimers.
#
# Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimers in the documentation
# and/or other materials provided with the distribution.
#
# Neither the names of Advanced Micro Devices, Inc., nor the names of its
# contributors may be used to endorse or promote products derived from this
# Software without specific prior written permission.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
# THE SOFTWARE.
#===----------------------------------------------------------------------===#

WORK_DIR="$PWD"
CURR_DIR="$PWD"

compRegx='aocc-compiler*tar*'
gCompStr="AOCC Compiler"

gCompTar=""

gPkgDir=""

comScript=""
gActualCompFldr=""

moduleScript=""
g_comp_folder_name=""
g_fl_set_env="setenv_AOCC.sh"
g_inst_fl_name="install.sh"

g_loc_lib_path=""

Usage()
{
	echo ""
	echo -e "This script generates ${g_fl_set_env} file which can be used to setup shell environment for using AOCC compiler.\n"
	echo "This script uses following packages:"
	echo -e "\t(1) $gCompStr"
	echo -e "\nIf you don't have any of above packages then please contact AOCC team to get these packages"
	echo -e "\nUsage:"
	echo -e "\tExample-1: Execute ${g_inst_fl_name}"
	echo -e "\t bash ${g_inst_fl_name}"
	echo ""
}

Fail_CorruptFolder()
{
	var="$1"

	echo "ERROR: $var folder seems to be corrupt !"
	echo "Download fresh package and try"
	RemoveEnvFiles
}

StartSetEnvScript()
{
	DATE=$(date +'%c' | sed 's/[: ]/_/g')

	comScript="${WORK_DIR}/setenv_AOCC_${DATE}.sh"
	moduleScript="${WORK_DIR}/aocc_module_${DATE}.sh"

	InitSetEnvFile
	ret1=$?

	InitModuleFile
	ret2=$?

	if [[ ($ret1 -ne 0) || ($ret1 -ne 0) ]];then
		echo "Error: Unable to write in dir:${WORK_DIR}"
		retVal=-1
	else
		retVal=0
	fi

	return $retVal
}


InitSetEnvFile()
{
retVal=0

	echo ' '>$comScript
	retVal=$?

	return $retVal
}


InitModuleFile()
{
retVal=0

	echo '#%Module1.0#####################################################################'>$moduleScript
	echo " " >>$moduleScript
	echo 'proc ModulesHelp { } {' >>$moduleScript
	echo '    global version AOCChome' >>$moduleScript
 	echo '    puts stderr "\tAOCC \n"' >>$moduleScript
 	echo '    puts stderr "\tloads AOCC compiler setup \n"' >>$moduleScript
 	echo '}' >>$moduleScript
 	echo " " >>$moduleScript
	echo 'module-whatis "loads AOCC compiler setup "' >>$moduleScript
	echo " " >>$moduleScript
	retVal=$?

	return $retVal
}

SetEnvFile()
{
msg=$1

echo "$msg" >>$comScript

}

ModuleFile()
{
msg=$1

echo $msg >>$moduleScript

}

CopySetEnvFile()
{
	cp $comScript ${WORK_DIR}/${g_fl_set_env}
	if [[ $? -ne 0 ]];then
		echo "Error: Unable copy $comScript to ${WORK_DIR}/${g_fl_set_env}"
		retVal=-1
	else
		rm -f $comScript &>/dev/null
		comScript=${WORK_DIR}/${g_fl_set_env}
		echo -e "Successfully generated setenv file:$comScript"
		retVal=0
	fi

return $retVal
}

CopyModuleFile()
{

	m_fl_name="${g_comp_folder_name}_module"
	cp $moduleScript ${WORK_DIR}/$m_fl_name
	if [[ $? -ne 0 ]];then
		echo "Error: Unable copy $moduleScript to ${WORK_DIR}/$m_fl_name"
		retVal=-1
	else
		rm -f $moduleScript &>/dev/null
		moduleScript=${WORK_DIR}/$m_fl_name
		retVal=0
	fi

return $retVal
}

EndSetEnvScript()
{
retVal=0

	if [[ -e "${WORK_DIR}/${g_fl_set_env}" ]];then
		rm -rf "${WORK_DIR}/${g_fl_set_env}" &>/dev/null
	fi

	CopySetEnvFile
	ret1=$?

	CopyModuleFile
	ret2=$?

	if [[ ($ret1 -ne 0) || ($ret2 -ne 0) ]];then
		retVal=-1
	fi

return $retVal
}

RemoveFile()
{
FILE_ABS_PATH=$1

	if [[ -f "$FILE_ABS_PATH" ]];then
		rm -f $FILE_ABS_PATH &>/dev/null
		if [[ $? -ne 0 ]];then
			echo "WARNING: Unable to remove existing file $FILE_ABS_PATH"
		fi
	fi
}


CleanUp()
{
	rm -rf $comScript &>/dev/null
	rm -rf $moduleScript &>/dev/null
}


AlternativeVersionCheck()
{
	inputName=$1
	comp_libry_fldr=$2
	fileName=$(echo $inputName | awk -F'.so' '{print $1}')
	fileName="${fileName}.so"
	alternativeVersionFile=$(ldconfig --print | grep $fileName | awk -F'=>' '{print $2}' | tr '\n' ' ' |  awk -F' ' '{print $1}')

	if [[ -e $alternativeVersionFile ]];then
		ln -s $alternativeVersionFile $comp_libry_fldr/$inputName &>/dev/null
	fi
}


CheckForMissingDynLibs()
{
fRetVal=0
comp_folder="$1"
comp_bin="$comp_folder/bin"
comp_libry="$comp_folder/lib"
missing_libs_file="check_missing_files.txt"
uniq_missing_lib_names_file="un_${missing_libs_file}"
ary=("clang" "clang++" "flang")


rm -f $missing_libs_file &>/dev/null
export LD_LIBRARY_PATH=$comp_libry:$LD_LIBRARY_PATH
missing_count=0
for((i=0;i<${#ary[@]};i++))
do
        exe_name=${ary[$i]}
        ldd ${comp_bin}/$exe_name | grep 'not found' >>$missing_libs_file
        retVal=$?
        if [[ $retVal -eq 0 ]];then
                let "missing_count=missing_count+1"
        fi
done

sort $missing_libs_file | uniq | awk -F'=>' '{print $1}' | sed 's/[ \t]*//g' &>$uniq_missing_lib_names_file

if [[ $missing_count -ne 0 ]];then
	while read line ; do
		AlternativeVersionCheck "$line" "$comp_libry"
	done < $uniq_missing_lib_names_file

	rm -f $missing_libs_file &>/dev/null
	rm -f $uniq_missing_lib_names_file &>/dev/null

	missing_count=0
	for((i=0;i<${#ary[@]};i++))
	do
		exe_name=${ary[$i]}
		ldd ${comp_bin}/$exe_name | grep 'not found' >>$missing_libs_file
		retVal=$?
		if [[ $retVal -eq 0 ]];then
			let "missing_count=missing_count+1"
		fi
	done

	if [[ $missing_count -ne 0 ]];then
		sort $missing_libs_file | uniq | awk -F'=>' '{print $1}' | sed 's/[ \t]*//g' &>$uniq_missing_lib_names_file
		echo "ERROR:Please install following libraries for clang to work:"
		echo "After installing these libraries please run this ${g_inst_fl_name} again"

		index=0
		while read line ; do
		    index=$(($index+1))
		    echo -e "    ($index) $line"
		done < $uniq_missing_lib_names_file

		fRetVal=-1
	else
		fRetVal=0
	fi
fi

rm -f $missing_libs_file &>/dev/null
rm -f $uniq_missing_lib_names_file &>/dev/null

return $fRetVal
}

HandleCompTar()
{
retVal=0

	if [[ -d "${gActualCompFldr}/bin" ]];then

		g_comp_folder_name=$(basename $gActualCompFldr)
		compBin="${gActualCompFldr}/bin"

		SetEnvFile "export PATH=${compBin}:\$PATH"
		SetEnvFile "export PATH=${gActualCompFldr}/share/opt-viewer:\$PATH"
		ModuleFile "set    AOCChome    ${gActualCompFldr}"
		ModuleFile "prepend-path    PATH    \$AOCChome/share/opt-viewer"
		ModuleFile "prepend-path    PATH    \$AOCChome/bin"

		SetEnvFile "export LIBRARY_PATH=${gActualCompFldr}/lib:${gActualCompFldr}/lib32:\$LIBRARY_PATH"
		ModuleFile "prepend-path    LIBRARY_PATH    \$AOCChome/lib"
		ModuleFile "prepend-path    LIBRARY_PATH    \$AOCChome/lib32"

		SetEnvFile "export LD_LIBRARY_PATH=${gActualCompFldr}/ompd:${gActualCompFldr}/lib:${gActualCompFldr}/lib32:\$LD_LIBRARY_PATH"
		ModuleFile "prepend-path    LD_LIBRARY_PATH    \$AOCChome/ompd"
		ModuleFile "prepend-path    LD_LIBRARY_PATH    \$AOCChome/lib"
		ModuleFile "prepend-path    LD_LIBRARY_PATH    \$AOCChome/lib32"

                SetEnvFile ""
                SetEnvFile "if [[ -z \$C_INCLUDE_PATH ]];then"
                SetEnvFile "    export C_INCLUDE_PATH=${gActualCompFldr}/include"
                SetEnvFile "else"
                SetEnvFile "    export C_INCLUDE_PATH=\$C_INCLUDE_PATH:${gActualCompFldr}/include"
                SetEnvFile "fi"
                SetEnvFile ""
                ModuleFile "prepend-path    C_INCLUDE_PATH     \$AOCChome/include"

                SetEnvFile ""
                SetEnvFile "if [[ -z \$CPLUS_INCLUDE_PATH ]];then"
                SetEnvFile "    export CPLUS_INCLUDE_PATH=${gActualCompFldr}/include"
                SetEnvFile "else"
                SetEnvFile "    export CPLUS_INCLUDE_PATH=\$CPLUS_INCLUDE_PATH:${gActualCompFldr}/include"
                SetEnvFile "fi"
                SetEnvFile ""
		ModuleFile "prepend-path    CPLUS_INCLUDE_PATH    \$AOCChome/include"

		CheckForMissingDynLibs "${gActualCompFldr}"
		retVal=$?

	else
		Fail_CorruptFolder "$gCompStr"
		retVal=-1
	fi


return $retVal
}

add_to_loc()
{
fldr=$1
        if [[ $g_loc_lib_path != "" ]];then
                g_loc_lib_path="$fldr:$g_loc_lib_path"
        else
                g_loc_lib_path="$fldr"
        fi
}

HandleLibEnvSetting()
{
        if [[ -d '/usr/lib32' ]];then
                add_to_loc '/usr/lib32'
        fi

        if [[ -d '/usr/lib' ]];then
                add_to_loc '/usr/lib'
        fi

        if [[ -d '/usr/lib/x86_64-linux-gnu' ]];then
                add_to_loc '/usr/lib/x86_64-linux-gnu'
        fi

        if [[ -d '/usr/lib64' ]];then
                add_to_loc '/usr/lib64'
        fi

        if [[ $g_loc_lib_path != "" ]];then
                SetEnvFile "export LIBRARY_PATH=$g_loc_lib_path:\$LIBRARY_PATH"
                SetEnvFile "export LD_LIBRARY_PATH=$g_loc_lib_path:\$LD_LIBRARY_PATH"

                ModuleFile "prepend-path    LIBRARY_PATH    ${g_loc_lib_path}"
                ModuleFile "prepend-path    LD_LIBRARY_PATH    ${g_loc_lib_path}"
        fi
}

EndUsageExample()
{
	echo -e "\nAOCC installation is complete"
	echo -e "\nCompiler has been installed in following location:"
	source $comScript
	which clang
	which clang++
	which flang

	echo -e "\nSteps to setup AOCC:"
	echo -e "\t(1) Setup AOCC environment by executing below command:"
	echo -e "\t\tsource $comScript"
	echo -e "\n\t(2) For location and version of AOCC's clang enter commands given below"
	echo -e "\t\twhich clang"
	echo -e "\t\tclang -v"
	echo ""

}

HandleScrptAndPkgFldr()
{
	invoked_script=$(readlink -f $0)
	gComilerFolderContainingInstallFile=$(dirname $invoked_script)
	gParentOfCompfolder=$(dirname $gComilerFolderContainingInstallFile)
	gPkgDir=$gParentOfCompfolder
	gActualCompFldr=$gComilerFolderContainingInstallFile

	cd $gComilerFolderContainingInstallFile

	WORK_DIR=$gPkgDir
	cd $WORK_DIR

	gCompTar=$(ls -rt ${gPkgDir}/$compRegx 2>/dev/null | head -n1)
}


fin=0
if [[ $# -ne 0 ]];then
	if [[ 	($1 == "-h") || 
		($1 == "--help")  ]];then
		Usage
		fin=1
	else
		echo -e "\nERROR:Invalid command line option $1"
		echo -e "\tUse \"bash ${g_inst_fl_name} -h \" for help\n"
		fin=1
	fi
fi

if [[ $fin -eq 0 ]];then
	HandleScrptAndPkgFldr
	if [[ $? -eq 0 ]];then
		StartSetEnvScript
		if [[ $? -eq 0 ]];then
			HandleLibEnvSetting
			if [[ $? -eq 0 ]];then
				HandleCompTar
				EndSetEnvScript
				if [[ $? -eq 0 ]];then
					EndUsageExample
				fi
			else
				CleanUp
			fi
		fi
	fi
fi
cd $CURR_DIR



