#!/bin/bash
# Copyright 2008-2023 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2

if [[ $1 == "--help" || $1 == "-h" ]] ; then
	cat <<-EOF
	Usage: emerge-wrapper [--target <chost>] <--init|commands for cross-emerge>

	emerge-wrapper is used in one of two ways:
	  - Use --init to setup cross-toolchain environment(s)
	  - Pass the command line through to cross-emerge
	EOF
	exit 0
fi

PREFIX="/usr"
# Enable this script to be manually installed while debugging
[[ ${PREFIX} == "@"PREFIX"@" ]] && PREFIX="/usr"

err() { echo "emerge-wrapper: ERROR: $*" 1>&2; exit 1; }

emit_setup_warning()
{
	if ! ${setup_warning} ; then
		setup_warning=true
		echo "!!! WARNING - Cannot auto-configure CHOST ${CHOST};"
		echo "!!! You should edit ${confs[*]}"
		echo "!!! by hand to complete your configuration."
	fi
	echo "!!!  $*"
}

cross_wrap_etc()
{
	[[ $1 == "-q" ]] || echo "${CHOST}: setting up cross basics in ${SYSROOT}/etc"

	setup_warning=false

	cp -a "${PREFIX}"/share/crossdev/etc ${SYSROOT}/     || return 1
	ln -snf "${MAIN_REPO_PATH}/profiles/embedded" "${SYSROOT}/etc/portage/make.profile" || return 1

	local confs=(
		${SYSROOT}/etc/portage/make.conf
		${SYSROOT}/etc/portage/profile/make.defaults
		${SYSROOT}/etc/portage/profile/use.force
	)

	# Re-use existing CHOST->portage ARCH mapping code
	ARCH=$(
		inherit() { :; }
		die() { err "toolchain-funcs.eclass$*"; }
		EAPI=7 . "${MAIN_REPO_PATH}"/eclass/toolchain-funcs.eclass
		tc-arch
	)
	[[ $? -ne 0 ]] && err "Failed calling 'tc-arch' from toolchain-funcs.eclass."
	[[ ${ARCH} == "unknown" ]] && emit_setup_warning "No ARCH is known for this target."

	LIBC="__LIBC__"
	case ${CHOST} in
	*gnu*)    LIBC=glibc ;;
	*uclibc*) LIBC=uclibc-ng ;;
	*musl*)   LIBC=musl ;;
	*cygwin*) LIBC=Cygwin ;;
	*mingw*)  LIBC=mingw ;;
	nvptx*|*-newlib|*-elf|*-eabi) LIBC=newlib ;;
	*)        emit_setup_warning "No LIBC is known for this target." ;;
	esac

	KERNEL="__KERNEL__"
	case ${CHOST} in
	*linux*)  KERNEL=linux ;;
	*mingw*)  KERNEL=Winnt ;;
	*)        emit_setup_warning "No KERNEL is known for this target." ;;
	esac
	if [[ -n ${KERNEL} ]]; then
		USE_FORCE_KERNEL="kernel_${KERNEL}"
	else
		USE_FORCE_KERNEL=""
	fi

	sed -i \
		-e "s:__LIBC__:${LIBC}:g" \
		-e "s:__ARCH__:${ARCH}:g" \
		-e "s:__KERNEL__:${KERNEL}:g" \
		-e "s:__USE_FORCE_KERNEL__:${USE_FORCE_KERNEL}:g" \
		-e "s:__CHOST__:${CHOST}:g" \
		-e "s:__CBUILD__:${CBUILD}:g" \
		"${confs[@]}"

	if [[ "${LLVM}" == "yes" ]] ; then
		cat <<-EOF >>${SYSROOT}/etc/portage/profile/make.defaults
	AR=llvm-ar
	AS=llvm-as
	CC="${CHOST}-clang"
	CROSS_COMPILE="${CHOST}-"
	CXX="${CHOST}-clang++"
	DLLTOOL=llvm-dlltool
	HOSTCC="${CC:=clang}"
	HOSTCXX="${CXX:=clang++}"
	LD=ld.lld
	LLVM=1
	NM=llvm-nm
	OBJCOPY=llvm-objcopy
	RANLIB=llvm-ranlib
	READELF=llvm-readelf
	STRIP=llvm-strip
	EOF
	fi

	return 0
}

cross_wrap_bin()
{
	[[ $1 == "-q" ]] || echo "${CHOST}: Setting up symlinks"

	pushd "${0%/*}" >/dev/null
	local wrapper
	for wrapper in ebuild emerge fix-root pkg-config ; do
		ln -sf cross-${wrapper} ${CHOST}-${wrapper}
	done
	# some people like their tab completion
	ln -sf cross-emerge emerge-${CHOST}
	popd >/dev/null
}

cross_wrap()
{
	SYSROOT=/usr/${CHOST}
	cross_wrap_bin "$@" || return $?
	if [[ -d ${SYSROOT} ]] && [[ ! -d ${SYSROOT}/etc ]] ; then
		cross_wrap_etc "$@"
	fi
	return $?
}

cross_init()
{
	if [[ ${CHOST} == "wrapper" ]] ; then
		err "missing --target <CHOST> option"
	fi

	# Initialize env for just one target.  This is the automated behavior
	# when crossdev is setting things up for people.
	cross_wrap -q
}

# CBUILD must be the first thing we export, but might as well avoid
# running portageq multiple times ...
import_vars="DISTDIR MAKEOPTS GENTOO_MIRRORS"
eval $(portageq envvar -v CBUILD ${import_vars})
export CBUILD

MAIN_REPO_PATH=$(crossdev --show-repo-cfg MAIN_REPO_PATH)

# Get default CHOST value from program name
CHOST=${0##*/}
CHOST=${CHOST%-emerge}
CHOST=${CHOST#emerge-}
export CHOST

if [[ $1 == "--target" ]] ; then
	CHOST=$2
	shift 2
fi

if [[ $1 == "--init" ]] ; then
	cross_init
	exit $?
fi

if [[ $CHOST == "wrapper" ]] ; then
	echo "After running this program with the --init option as root"
	echo "you can call it directly like emerge-wrapper --target CHOST <emerge options>"
	echo "or using the emerge-CHOST wrappers"
	exit 1
fi

type -P -- ${CHOST}-gcc >/dev/null || err "you need to 'crossdev $CHOST' first"

exec cross-emerge "$@"
