mirror of
https://github.com/haskell/haskell-language-server.git
synced 2024-09-11 08:45:35 +03:00
This still makes sure that ghc has been compiled with the same core libraries as hls while it allows runtime environments where other packages have been added to the ghc-pkg database. This commit also adds that file to the sdist, so that distro packagers can use it. Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
187 lines
6.1 KiB
Bash
187 lines
6.1 KiB
Bash
#!/bin/sh
|
|
|
|
exedir="@@EXE_DIR@@"
|
|
executablename="@@EXE_NAME@@"
|
|
GHC_VERSION="@@GHC_VERSION@@"
|
|
|
|
# This space separated list contains the names and versions of the boot libraries used to compile hls.
|
|
BOOT_PKGS="@@BOOT_PKGS@@"
|
|
# This space separated list contains the ABI hashes of the pkgs in BOOT_PKGS at compiletime.
|
|
ABI_HASHES="@@ABI_HASHES@@"
|
|
|
|
debug_msg() {
|
|
if [ -n "$HLS_WRAPPER_DEBUG" ] ; then
|
|
(>&2 printf "\\033[0;34m%s\\033[0m\\n" "$1")
|
|
fi
|
|
}
|
|
|
|
err_msg() {
|
|
if [ -n "$HLS_WRAPPER_DEBUG" ] ; then
|
|
(>&2 printf "\\033[0;31m%s\\033[0m\\n" "$1")
|
|
elif [ -n "$HLS_WRAPPER_VERBOSE" ] ; then
|
|
(>&2 printf "\\033[0;31m%s\\033[0m\\n" "$1")
|
|
fi
|
|
}
|
|
|
|
instruction_msg() {
|
|
(>&2 printf "\\033[0;35m%s\\033[0m\\n" "$1")
|
|
}
|
|
|
|
err_exit() {
|
|
msg="Couldn't find a working/matching GHC installation. Consider installing ghc-${GHC_VERSION} via ghcup or build HLS from source."
|
|
# adjust Content-Length when changing json
|
|
json="{\"jsonrpc\":\"2.0\", \"method\":\"window/showMessage\", \"params\": {\"type\": 1, \"message\": \"${msg}\"}}"
|
|
printf "%s\r\n" "Content-Length: 203"
|
|
printf "%s\r\n"
|
|
printf "%s" "${json}"
|
|
unset msg json
|
|
}
|
|
|
|
err_ghc_pkg() {
|
|
err_msg "Could not find a ghc-pkg binary (found: $1)!"
|
|
}
|
|
|
|
err_abi() {
|
|
err_msg "GHC ABIs don't match!"
|
|
err_msg ""
|
|
err_msg "Expected: ${ABI_HASHES}"
|
|
err_msg "Got: $1"
|
|
}
|
|
|
|
err_ver() {
|
|
err_msg "GHC versions don't match!"
|
|
err_msg ""
|
|
err_msg "Expected: ${GHC_VERSION}"
|
|
err_msg "Got: $1"
|
|
}
|
|
|
|
# Check the version of GHC and the ABI.
|
|
check_ghc() {
|
|
{ [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ] ;} && debug_msg "internal error: not enough arguments to check_ghc: 1:$1,2:$2,3:$3" && return 4
|
|
|
|
check_ghc_libdir=$1
|
|
check_ghc_bin=$2
|
|
GHC_PKG=$3
|
|
check_ghc_ver="$("${check_ghc_bin}" --numeric-version 2>/dev/null)"
|
|
|
|
# check version
|
|
if [ "${check_ghc_ver}" = "${GHC_VERSION}" ] ; then
|
|
# check for all packages listed in BOOT_PKGS that they are present with the same ABI hash as at hls-compiletime to prevent linking issues.
|
|
if "${GHC_PKG}" --version >/dev/null ; then
|
|
:
|
|
elif "${GHC_PKG}-${GHC_VERSION}" --version >/dev/null ; then
|
|
GHC_PKG=${GHC_PKG}-${GHC_VERSION}
|
|
else
|
|
err_ghc_pkg "${GHC_PKG}"
|
|
unset GHC_LIBDIR
|
|
return 1
|
|
fi
|
|
PKGCONF="${check_ghc_libdir}/package.conf.d"
|
|
MY_ABI_HASHES="$(for dep in ${BOOT_PKGS} ; do printf "%s:" "${dep}" && "${GHC_PKG}" --global --global-package-db "$PKGCONF" field "${dep}" abi --simple-output ; done | tr '\n' ' ' | xargs)"
|
|
if [ "${ABI_HASHES}" != "${MY_ABI_HASHES}" ] ; then
|
|
err_abi "${MY_ABI_HASHES}"
|
|
return 3
|
|
fi
|
|
unset PKGCONF
|
|
else
|
|
err_ver "${check_ghc_ver}"
|
|
unset GHC_LIBDIR
|
|
return 2
|
|
fi
|
|
|
|
unset check_ghc_libdir check_ghc_bindir GHC_PKG check_ghc_ver
|
|
}
|
|
|
|
# Infer ghc-pkg from the given ghc path. Doesn't check for existence of any
|
|
# components.
|
|
infer_ghc_pkg() {
|
|
infer_ghc_path=$1
|
|
infer_ghc_bin=${infer_ghc_path##**/}
|
|
infer_ghc_ver_suffix=${infer_ghc_bin#ghc}
|
|
path_prefix="$(dirname "${infer_ghc_path}")"
|
|
|
|
if [ "${path_prefix}" = "." ] ; then
|
|
echo "ghc-pkg${infer_ghc_ver_suffix}"
|
|
elif [ "${path_prefix}" = "/" ] ; then
|
|
echo "${path_prefix}ghc-pkg${infer_ghc_ver_suffix}"
|
|
else
|
|
echo "${path_prefix}/ghc-pkg${infer_ghc_ver_suffix}"
|
|
fi
|
|
unset infer_ghc_path infer_ghc_bin infer_ghc_ver_suffix path_prefix
|
|
}
|
|
|
|
# try GHC_LIBDIR from the environment (e.g. user set it, or haskell-language-server-wrapper)
|
|
if [ -n "${GHC_LIBDIR}" ] &&
|
|
[ -n "${GHC_BIN}" ] &&
|
|
{ debug_msg "Trying method: GHC_LIBDIR and GHC_BIN from env" ; HLS_WRAPPER_VERBOSE=1 ; check_ghc "${GHC_LIBDIR}" "${GHC_BIN}" "$(infer_ghc_pkg "${GHC_BIN}")" || { err_exit ; exit 1 ; } ; }
|
|
then
|
|
:
|
|
# try GHC_BIN from the environment (e.g. user set it)
|
|
elif [ -n "${GHC_BIN}" ] &&
|
|
GHC_LIBDIR="$("${GHC_BIN}" --print-libdir)" &&
|
|
{ debug_msg "Trying method: GHC_BIN from env" ; HLS_WRAPPER_VERBOSE=1 ; check_ghc "${GHC_LIBDIR}" "${GHC_BIN}" "$(infer_ghc_pkg "${GHC_BIN}")" || { err_exit ; exit 2 ; } ; }
|
|
then
|
|
:
|
|
# try ghcup
|
|
elif command -v ghcup >/dev/null &&
|
|
GHC_BIN="$(ghcup whereis ghc "${GHC_VERSION}")" &&
|
|
GHC_LIBDIR="$("${GHC_BIN}" --print-libdir)" &&
|
|
{ debug_msg "Trying method: ghcup" ; check_ghc "${GHC_LIBDIR}" "${GHC_BIN}" "$(infer_ghc_pkg "${GHC_BIN}")" ; }
|
|
then
|
|
:
|
|
# try ghc-${GHC_VERSION}
|
|
elif command -v ghc-${GHC_VERSION} >/dev/null &&
|
|
GHC_LIBDIR="$("ghc-${GHC_VERSION}" --print-libdir)" &&
|
|
{ debug_msg "Trying method: ghc-${GHC_VERSION} in PATH" ; check_ghc "${GHC_LIBDIR}" "ghc-${GHC_VERSION}" "$(infer_ghc_pkg "ghc-${GHC_VERSION}")" ; }
|
|
then
|
|
:
|
|
# try ghc
|
|
elif command -v ghc >/dev/null &&
|
|
GHC_LIBDIR="$(ghc --print-libdir)" &&
|
|
{ debug_msg "Trying method: ghc in PATH" ; check_ghc "${GHC_LIBDIR}" "ghc" "$(infer_ghc_pkg "ghc")" ; }
|
|
then
|
|
:
|
|
# try stack
|
|
elif command -v stack >/dev/null &&
|
|
GHC_BIN="$(cd "$(mktemp -d)" && stack --no-system-ghc --no-install-ghc --resolver "ghc-${GHC_VERSION}" exec sh -- -c 'command -v ghc')" &&
|
|
GHC_LIBDIR="$("${GHC_BIN}" --print-libdir)" &&
|
|
{ debug_msg "Trying method: stack" ; check_ghc "${GHC_LIBDIR}" "${GHC_BIN}" "$(infer_ghc_pkg "${GHC_BIN}")" ; }
|
|
then
|
|
:
|
|
else
|
|
HLS_WRAPPER_VERBOSE=1
|
|
err_msg "All methods exhausted!"
|
|
err_exit
|
|
err_msg "exiting..."
|
|
exit 42
|
|
fi
|
|
|
|
debug_msg "Found GHC libdir at: ${GHC_LIBDIR}"
|
|
|
|
case "$(uname -s)" in
|
|
"Darwin"|"darwin")
|
|
if [ -n "$DYLD_LIBRARY_PATH" ] ; then
|
|
DYLD_LIBRARY_PATH="$(for i in "${GHC_LIBDIR}"/* ; do [ -d "$i" ] && printf "%s" "$i:" ; done)$DYLD_LIBRARY_PATH"
|
|
debug_msg "Exporting DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}"
|
|
export DYLD_LIBRARY_PATH
|
|
else
|
|
DYLD_LIBRARY_PATH="$(for i in "${GHC_LIBDIR}"/* ; do [ -d "$i" ] && printf "%s" "$i:" ; done | sed 's/:$//')"
|
|
debug_msg "Exporting DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}"
|
|
export DYLD_LIBRARY_PATH
|
|
fi
|
|
;;
|
|
*)
|
|
if [ -n "$LD_LIBRARY_PATH" ] ; then
|
|
LD_LIBRARY_PATH="$(for i in "${GHC_LIBDIR}"/* ; do [ -d "$i" ] && printf "%s" "$i:" ; done)$LD_LIBRARY_PATH"
|
|
debug_msg "Exporting LD_LIBRARY_PATH=${LD_LIBRARY_PATH}"
|
|
export LD_LIBRARY_PATH
|
|
else
|
|
LD_LIBRARY_PATH="$(for i in "${GHC_LIBDIR}"/* ; do [ -d "$i" ] && printf "%s" "$i:" ; done | sed 's/:$//')"
|
|
debug_msg "Exporting LD_LIBRARY_PATH=${LD_LIBRARY_PATH}"
|
|
export LD_LIBRARY_PATH
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
exec "${exedir}/${executablename}" ${1+"$@"}
|