mirror of
https://github.com/haskell/haskell-language-server.git
synced 2024-10-05 12:49:07 +03:00
f6dc2064d1
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+"$@"}
|