feat(ghc): enable cross-compiling haskell packages on CI

- `termux_setup_ghc_cross_compiler` should not be called by build.sh, as it installs cross-compiler
in $TERMUX_PREFIX (otherwise ghc adds wrong `rpaths` to built libs and executables)

Signed-off-by: Aditya Alok <dev.aditya.alok@gmail.com>
This commit is contained in:
Aditya Alok 2022-03-07 15:56:29 +05:30 committed by xtkoba
parent 80f7a2a0df
commit dc2474b2c2
12 changed files with 461 additions and 20 deletions

View File

@ -55,6 +55,24 @@ source "$TERMUX_SCRIPTDIR/scripts/build/termux_download.sh"
# shellcheck source=scripts/build/setup/termux_setup_ghc.sh
source "$TERMUX_SCRIPTDIR/scripts/build/setup/termux_setup_ghc.sh"
# Utility function to setup a GHC cross-compiler toolchain targeting Android.
# This function should be called before termux_create_timestamp, it installs ghc-libs in
# $TERMUX_PREFIX otherwise ghc writes other path as rpath.
# NOTE: It should never be called by build.sh. By default, it will be called automatically by
# `termux_step_get_dependencies` if `ghc-libs` or `ghc-libs-static`
# is in dependency of the package.
# shellcheck source=scripts/build/setup/termux_setup_ghc_cross_compiler.sh
source "$TERMUX_SCRIPTDIR/scripts/build/setup/termux_setup_ghc_cross_compiler.sh"
# Utility function to setup cabal-install (may be used by ghc toolchain).
# shellcheck source=scripts/build/setup/termux_setup_cabal.sh.
source "$TERMUX_SCRIPTDIR/scripts/build/setup/termux_setup_cabal.sh"
# Utility function to setup jailbreak-cabal. It is used to remove version constraints
# from Cabal packages.
# shellcheck source=scripts/build/setup/termux_setup_jailbreak_cabal.sh
source "$TERMUX_SCRIPTDIR/scripts/build/setup/termux_setup_jailbreak_cabal.sh"
# Utility function for setting up GN toolchain.
# shellcheck source=scripts/build/setup/termux_setup_gn.sh
source "$TERMUX_SCRIPTDIR/scripts/build/setup/termux_setup_gn.sh"
@ -195,6 +213,10 @@ source "$TERMUX_SCRIPTDIR/scripts/build/configure/termux_step_configure_cmake.sh
# shellcheck source=scripts/build/configure/termux_step_configure_meson.sh
source "$TERMUX_SCRIPTDIR/scripts/build/configure/termux_step_configure_meson.sh"
# Setup configure args and run haskell build system. This function is called from termux_step_configure.
# shellcheck source=scripts/build/configure/termux_step_configure_haskell_build.sh
source "$TERMUX_SCRIPTDIR/scripts/build/configure/termux_step_configure_haskell_build.sh"
# Configure the package
# shellcheck source=scripts/build/configure/termux_step_configure.sh
source "$TERMUX_SCRIPTDIR/scripts/build/configure/termux_step_configure.sh"
@ -251,9 +273,14 @@ termux_step_post_massage() {
return
}
# Create debscripts for haskell packages. This only executes for haskell lib packages.
# shellcheck source=scripts/build/haskell-build/termux_create_haskell_debscripts.sh
source "$TERMUX_SCRIPTDIR/scripts/build/haskell-build/termux_create_haskell_debscripts.sh"
# Hook function to create {pre,post}install, {pre,post}rm-scripts and similar
termux_step_create_debscripts() {
return
# This function is written here as it will allow overriding from build.sh.
termux_create_haskell_debscripts
}
# Convert Debian maintainer scripts into pacman-compatible installation hooks.

View File

@ -1,9 +1,15 @@
termux_step_configure() {
[ "$TERMUX_PKG_METAPACKAGE" = "true" ] && return
if [ "$TERMUX_PKG_FORCE_CMAKE" = "false" ] && [ -f "$TERMUX_PKG_SRCDIR/configure" ]; then
# This check should be above autotools check as haskell package too makes use of configure scripts which
# should be executed by its own build system.
if ls ./*.cabal &>/dev/null; then
[ "$TERMUX_CONTINUE_BUILD" == "true" ] && return
termux_setup_ghc
termux_step_configure_haskell_build
elif [ "$TERMUX_PKG_FORCE_CMAKE" = "false" ] && [ -f "$TERMUX_PKG_SRCDIR/configure" ]; then
if [ "$TERMUX_CONTINUE_BUILD" == "true" ]; then
return;
return
fi
termux_step_configure_autotools
elif [ "$TERMUX_PKG_FORCE_CMAKE" = "true" ] || [ -f "$TERMUX_PKG_SRCDIR/CMakeLists.txt" ]; then
@ -16,13 +22,13 @@ termux_step_configure() {
# internally, but cannot be configured with our
# termux_step_configure_cmake function (CMakeLists.txt
# is not in src dir)
if [ -f "$TERMUX_PKG_SRCDIR/CMakeLists.txt" ] && \
if [ -f "$TERMUX_PKG_SRCDIR/CMakeLists.txt" ] &&
[ "$TERMUX_CONTINUE_BUILD" == "false" ]; then
termux_step_configure_cmake
fi
elif [ -f "$TERMUX_PKG_SRCDIR/meson.build" ]; then
if [ "$TERMUX_CONTINUE_BUILD" == "true" ]; then
return;
return
fi
termux_step_configure_meson
fi

View File

@ -0,0 +1,156 @@
termux_step_configure_haskell_build() {
termux_setup_jailbreak_cabal
printf "%s" "Jailbreaking Cabal file..."
jailbreak-cabal "${TERMUX_PKG_SRCDIR}"/*.cabal && echo "done." || {
termux_error_exit "failed."
}
ENABLE_SHARED="--enable-shared"
if [ "$TERMUX_PKG_EXTRA_CONFIGURE_ARGS" != "${TERMUX_PKG_EXTRA_CONFIGURE_ARGS/--disable-shared/}" ]; then
ENABLE_SHARED=""
fi
DYNAMIC_EXECUTABLE="
--ghc-options=-dynamic
--enable-executable-dynamic
--disable-library-vanilla
"
if [ "$TERMUX_PKG_EXTRA_CONFIGURE_ARGS" != "${TERMUX_PKG_EXTRA_CONFIGURE_ARGS/--disable-executable-dynamic/}" ]; then
DYNAMIC_EXECUTABLE=""
fi
HOST_FLAG="--host=$TERMUX_HOST_PLATFORM"
if [ "$TERMUX_PKG_EXTRA_CONFIGURE_ARGS" != "${TERMUX_PKG_EXTRA_CONFIGURE_ARGS/--host=/}" ]; then
HOST_FLAG=""
fi
LIBEXEC_FLAG="--libexecdir=$TERMUX_PREFIX/libexec"
if [ "$TERMUX_PKG_EXTRA_CONFIGURE_ARGS" != "${TERMUX_PKG_EXTRA_CONFIGURE_ARGS/--libexecdir=/}" ]; then
LIBEXEC_FLAG=""
fi
QUIET_BUILD=
if [ "$TERMUX_QUIET_BUILD" = true ]; then
QUIET_BUILD="-v0"
fi
LIB_STRIPPING="--enable-library-stripping"
if [ "$TERMUX_PKG_EXTRA_CONFIGURE_ARGS" != "${TERMUX_PKG_EXTRA_CONFIGURE_ARGS/--disable-library-stripping=/}" ] || [ "$TERMUX_DEBUG_BUILD" = "true" ]; then
LIB_STRIPPING=""
fi
EXECUTABLE_STRIPPING="--enable-executable-stripping"
if [ "$TERMUX_PKG_EXTRA_CONFIGURE_ARGS" != "${TERMUX_PKG_EXTRA_CONFIGURE_ARGS/--disable-executable-stripping=/}" ] || [ "$TERMUX_DEBUG_BUILD" = "true" ]; then
EXECUTABLE_STRIPPING=""
fi
SPLIT_SECTIONS="--enable-split-sections"
if [ "$TERMUX_PKG_EXTRA_CONFIGURE_ARGS" != "${TERMUX_PKG_EXTRA_CONFIGURE_ARGS/--disable-split-sections=/}" ]; then
SPLIT_SECTIONS=""
fi
# Avoid gnulib wrapping of functions when cross compiling. See
# http://wiki.osdev.org/Cross-Porting_Software#Gnulib
# https://gitlab.com/sortix/sortix/wikis/Gnulib
# https://github.com/termux/termux-packages/issues/76
AVOID_GNULIB=""
AVOID_GNULIB+=" ac_cv_func_nl_langinfo=yes"
AVOID_GNULIB+=" ac_cv_func_calloc_0_nonnull=yes"
AVOID_GNULIB+=" ac_cv_func_chown_works=yes"
AVOID_GNULIB+=" ac_cv_func_getgroups_works=yes"
AVOID_GNULIB+=" ac_cv_func_malloc_0_nonnull=yes"
AVOID_GNULIB+=" ac_cv_func_posix_spawn=no"
AVOID_GNULIB+=" ac_cv_func_posix_spawnp=no"
AVOID_GNULIB+=" ac_cv_func_realloc_0_nonnull=yes"
AVOID_GNULIB+=" am_cv_func_working_getline=yes"
AVOID_GNULIB+=" gl_cv_func_dup2_works=yes"
AVOID_GNULIB+=" gl_cv_func_fcntl_f_dupfd_cloexec=yes"
AVOID_GNULIB+=" gl_cv_func_fcntl_f_dupfd_works=yes"
AVOID_GNULIB+=" gl_cv_func_fnmatch_posix=yes"
AVOID_GNULIB+=" gl_cv_func_getcwd_abort_bug=no"
AVOID_GNULIB+=" gl_cv_func_getcwd_null=yes"
AVOID_GNULIB+=" gl_cv_func_getcwd_path_max=yes"
AVOID_GNULIB+=" gl_cv_func_getcwd_posix_signature=yes"
AVOID_GNULIB+=" gl_cv_func_gettimeofday_clobber=no"
AVOID_GNULIB+=" gl_cv_func_gettimeofday_posix_signature=yes"
AVOID_GNULIB+=" gl_cv_func_link_works=yes"
AVOID_GNULIB+=" gl_cv_func_lstat_dereferences_slashed_symlink=yes"
AVOID_GNULIB+=" gl_cv_func_malloc_0_nonnull=yes"
AVOID_GNULIB+=" gl_cv_func_memchr_works=yes"
AVOID_GNULIB+=" gl_cv_func_mkdir_trailing_dot_works=yes"
AVOID_GNULIB+=" gl_cv_func_mkdir_trailing_slash_works=yes"
AVOID_GNULIB+=" gl_cv_func_mkfifo_works=yes"
AVOID_GNULIB+=" gl_cv_func_mknod_works=yes"
AVOID_GNULIB+=" gl_cv_func_realpath_works=yes"
AVOID_GNULIB+=" gl_cv_func_select_detects_ebadf=yes"
AVOID_GNULIB+=" gl_cv_func_snprintf_posix=yes"
AVOID_GNULIB+=" gl_cv_func_snprintf_retval_c99=yes"
AVOID_GNULIB+=" gl_cv_func_snprintf_truncation_c99=yes"
AVOID_GNULIB+=" gl_cv_func_stat_dir_slash=yes"
AVOID_GNULIB+=" gl_cv_func_stat_file_slash=yes"
AVOID_GNULIB+=" gl_cv_func_strerror_0_works=yes"
AVOID_GNULIB+=" gl_cv_func_strtold_works=yes"
AVOID_GNULIB+=" gl_cv_func_symlink_works=yes"
AVOID_GNULIB+=" gl_cv_func_tzset_clobber=no"
AVOID_GNULIB+=" gl_cv_func_unlink_honors_slashes=yes"
AVOID_GNULIB+=" gl_cv_func_unlink_honors_slashes=yes"
AVOID_GNULIB+=" gl_cv_func_vsnprintf_posix=yes"
AVOID_GNULIB+=" gl_cv_func_vsnprintf_zerosize_c99=yes"
AVOID_GNULIB+=" gl_cv_func_wcrtomb_works=yes"
AVOID_GNULIB+=" gl_cv_func_wcwidth_works=yes"
AVOID_GNULIB+=" gl_cv_func_working_getdelim=yes"
AVOID_GNULIB+=" gl_cv_func_working_mkstemp=yes"
AVOID_GNULIB+=" gl_cv_func_working_mktime=yes"
AVOID_GNULIB+=" gl_cv_func_working_strerror=yes"
AVOID_GNULIB+=" gl_cv_header_working_fcntl_h=yes"
AVOID_GNULIB+=" gl_cv_C_locale_sans_EILSEQ=yes"
# Some packages rely on cabal build, therefore they may not have Setup.hs, (though very rare case)
# as cabal has that configured by default.
if [ ! -f "${TERMUX_PKG_SRCDIR}/Setup.hs" ] && [ ! -f "${TERMUX_PKG_SRCDIR}/Setup.lhs" ]; then
echo "Warning: No Setup.{hs,lhs} file found in ${TERMUX_PKG_SRCDIR}."
echo "Using default Setup.hs..."
cp "${TERMUX_SCRIPTDIR}/scripts/build/haskell-build/default-setup.hs" "${TERMUX_PKG_SRCDIR}/Setup.hs"
fi
LLVM_BACKEND=""
[ "${TERMUX_ARCH}" != "i686" ] && {
LLVM_BACKEND="-fllvm --ghc-option=-fllvm"
}
[ "$TERMUX_DEBUG_BUILD" = "true" ] && OPTIMISATION="-O0" || OPTIMISATION="-O"
# NOTE: We do not want to quote AVOID_GNULIB as we want word expansion.
# shellcheck disable=SC2086
env $AVOID_GNULIB runhaskell Setup configure \
$OPTIMISATION \
--prefix=$TERMUX_PREFIX \
--configure-option=--disable-rpath \
--configure-option=--disable-rpath-hack \
--configure-option=--host=$HOST_FLAG \
--ghc-option=-optl-Wl,-rpath=$TERMUX_PREFIX/lib \
--ghc-option=-optl-Wl,--enable-new-dtags \
--with-compiler=$(command -v termux-ghc) \
--with-ghc-pkg=$(command -v termux-ghc-pkg) \
--with-hsc2hs=$(command -v termux-hsc2hs) \
--hsc2hs-option=--cross-compile \
--with-ld=$LD \
--with-strip=$STRIP \
--with-ar=$AR \
--with-pkg-config=$PKG_CONFIG \
--with-happy=$(command -v happy) \
--with-alex=$(command -v alex) \
--with-runghc=$(command -v runghc) \
--extra-include-dirs=$TERMUX_PREFIX/include \
--extra-lib-dirs=$TERMUX_PREFIX/lib \
--disable-tests \
$LLVM_BACKEND \
$SPLIT_SECTIONS \
$EXECUTABLE_STRIPPING \
$LIB_STRIPPING \
$TERMUX_PKG_EXTRA_CONFIGURE_ARGS \
$ENABLE_SHARED \
$QUIET_BUILD \
$LIBEXEC_FLAG \
$DYNAMIC_EXECUTABLE
}

View File

@ -0,0 +1,3 @@
import Distribution.Simple
main :: IO ()
main = defaultMain

View File

@ -0,0 +1,17 @@
termux_create_haskell_debscripts() {
if [ "${TERMUX_PKG_IS_HASKELL_LIB}" = true ]; then
cat <<-EOF >./postinst
#!${TERMUX_PREFIX}/bin/sh
sh ${TERMUX_PREFIX}/share/haskell/register/${TERMUX_PKG_NAME}.sh
EOF
cat <<-EOF >./prerm
#!${TERMUX_PREFIX}/bin/sh
if [ "${TERMUX_PACKAGE_FORMAT}" = "pacman" ] || [ "\$1" = "remove" ] || [ "\$1" = "update" ]; then
sh ${TERMUX_PREFIX}/share/haskell/unregister/${TERMUX_PKG_NAME}.sh
fi
EOF
else
return 0
fi
}

View File

@ -0,0 +1,35 @@
termux_setup_cabal() {
if [ "${TERMUX_ON_DEVICE_BUILD}" = "false" ]; then
local TERMUX_CABAL_VERSION=3.6.2.0
local TERMUX_CABAL_TAR="${TERMUX_COMMON_CACHEDIR}/cabal-${TERMUX_CABAL_VERSION}.tar.xz"
local TERMUX_CABAL_RUNTIME_FOLDER
if [ "${TERMUX_PACKAGES_OFFLINE-false}" = "true" ]; then
TERMUX_CABAL_RUNTIME_FOLDER="${TERMUX_SCRIPTDIR}/build-tools/cabal-${TERMUX_CABAL_VERSION}-runtime"
else
TERMUX_CABAL_RUNTIME_FOLDER="${TERMUX_COMMON_CACHEDIR}/cabal-${TERMUX_CABAL_VERSION}-runtime"
fi
export PATH="${TERMUX_CABAL_RUNTIME_FOLDER}:${PATH}"
[ -d "${TERMUX_CABAL_RUNTIME_FOLDER}" ] && return
termux_download "https://github.com/MrAdityaAlok/ghc-cross-tools/releases/download/cabal-install-v${TERMUX_CABAL_VERSION}/cabal-install-${TERMUX_CABAL_VERSION}.tar.xz" \
"${TERMUX_CABAL_TAR}" \
"54de3ac03f9648a7e71715c1c4cba3ada34d9d20c812f39d134545e3e32708d4"
mkdir -p "${TERMUX_CABAL_RUNTIME_FOLDER}"
tar xf "${TERMUX_CABAL_TAR}" -C "${TERMUX_CABAL_RUNTIME_FOLDER}"
rm "${TERMUX_CABAL_TAR}"
cabal update
else
if [[ "$TERMUX_MAIN_PACKAGE_FORMAT" = "debian" && "$(dpkg-query -W -f '${db:Status-Status}\n' cabal-install 2>/dev/null)" != "installed" ]] ||
[[ "$TERMUX_MAIN_PACKAGE_FORMAT" = "pacman" && ! "$(pacman -Q cabal-install 2>/dev/null)" ]]; then
echo "Package 'cabal-install' is not installed."
exit 1
fi
fi
}

View File

@ -1,7 +1,7 @@
# Utility function to setup a GHC toolchain.
termux_setup_ghc() {
if [ "$TERMUX_ON_DEVICE_BUILD" = "false" ]; then
local TERMUX_GHC_VERSION=8.10.1
local TERMUX_GHC_VERSION=8.10.7
local TERMUX_GHC_TEMP_FOLDER="${TERMUX_COMMON_CACHEDIR}/ghc-${TERMUX_GHC_VERSION}"
local TERMUX_GHC_TAR="${TERMUX_GHC_TEMP_FOLDER}.tar.xz"
local TERMUX_GHC_RUNTIME_FOLDER
@ -14,26 +14,47 @@ termux_setup_ghc() {
export PATH="$TERMUX_GHC_RUNTIME_FOLDER/bin:$PATH"
if [ -d "$TERMUX_GHC_RUNTIME_FOLDER" ]; then return; fi
[ -d "$TERMUX_GHC_RUNTIME_FOLDER" ] && return
termux_download "https://downloads.haskell.org/~ghc/${TERMUX_GHC_VERSION}/ghc-${TERMUX_GHC_VERSION}-x86_64-deb10-linux.tar.xz" \
"$TERMUX_GHC_TAR" \
c1e31d798b013699b3c0de4fda27fb4cda47f572df0e75e3bd598a3012060615
a13719bca87a0d3ac0c7d4157a4e60887009a7f1a8dbe95c4759ec413e086d30
rm -Rf "$TERMUX_GHC_TEMP_FOLDER"
tar xf "$TERMUX_GHC_TAR" -C "$TERMUX_COMMON_CACHEDIR"
(set -e
(
set -e
unset CC CXX CFLAGS CXXFLAGS CPPFLAGS LDFLAGS AR AS CPP LD RANLIB READELF STRIP
cd "$TERMUX_GHC_TEMP_FOLDER"
./configure --prefix="$TERMUX_GHC_RUNTIME_FOLDER"
make install
)
rm -Rf "$TERMUX_GHC_TEMP_FOLDER"
# Cabal passes a host string to the libraries' configure scripts that isn't valid.
# After this patch we need to always pass --configure-option=--host=${TERMUX_HOST_PLATFORM}
# to Setup.hs configure.
(
CABAL_TEMP_FOLDER="$(mktemp -d cabal.XXXXXX)"
cd "${CABAL_TEMP_FOLDER}"
mkdir -p Cabal-3.6.2.0
curl -Ls \
https://hackage.haskell.org/package/Cabal-3.6.2.0/Cabal-3.6.2.0.tar.gz |
tar xzf - -C Cabal-3.6.2.0 --strip-components=1
cd Cabal-3.6.2.0
sed -i 's/maybeHostFlag = i/maybeHostFlag = [] -- i/' src/Distribution/Simple.hs
runhaskell Setup configure --prefix="${TERMUX_GHC_RUNTIME_FOLDER}"
runhaskell Setup build
runhaskell Setup install
ghc-pkg recache
)
rm -Rf "$TERMUX_GHC_TEMP_FOLDER" "$TERMUX_GHC_TAR"
else
if [[ "$TERMUX_MAIN_PACKAGE_FORMAT" = "debian" && "$(dpkg-query -W -f '${db:Status-Status}\n' ghc 2>/dev/null)" != "installed" ]] ||
[[ "$TERMUX_MAIN_PACKAGE_FORMAT" = "pacman" && ! "$(pacman -Q ghc 2>/dev/null)" ]]; then
[[ "$TERMUX_MAIN_PACKAGE_FORMAT" = "pacman" && ! "$(pacman -Q ghc 2>/dev/null)" ]]; then
echo "Package 'ghc' is not installed."
exit 1
fi

View File

@ -0,0 +1,83 @@
# Utility function to setup a GHC cross-compiler toolchain targeting Android.
# This function should be called before termux_create_timestamp. By default,
# it will be called automatically by `termux_step_get_dependencies` if `ghc-libs` or `ghc-libs-static`
# is in dependency of the package.
termux_setup_ghc_cross_compiler() {
local TERMUX_GHC_VERSION="8.10.7"
local GHC_PREFIX="ghc-cross-${TERMUX_GHC_VERSION}-${TERMUX_ARCH}"
if [ "${TERMUX_ON_DEVICE_BUILD}" = "false" ]; then
local TERMUX_GHC_RUNTIME_FOLDER
if [ "${TERMUX_PACKAGES_OFFLINE-false}" = "true" ]; then
TERMUX_GHC_RUNTIME_FOLDER="${TERMUX_SCRIPTDIR}/build-tools/${GHC_PREFIX}-runtime"
else
TERMUX_GHC_RUNTIME_FOLDER="${TERMUX_COMMON_CACHEDIR}/${GHC_PREFIX}-runtime"
fi
local GHC_BIN="${TERMUX_GHC_RUNTIME_FOLDER}/${TERMUX_ARCH}/bin"
local TERMUX_GHC_TAR="${TERMUX_COMMON_CACHEDIR}/${GHC_PREFIX}.tar.xz"
export PATH="${GHC_BIN}:${PATH}"
[ -d "${GHC_BIN}" ] && return
local CHECKSUMS="$(
cat <<-EOF
aarch64:f0324496eb5c072465f614a03492743ae28270d1844f08129ebc2b2f3148d331
arm:c7e2850d2b6e0905d7f68eb1be7119759c2e50ef0bff7243e58b86172d710a80
i686:86d7b38371b9098425b1abbffa667237f2624e079e3c65636b78f1b737e74891
x86_64:2704c3f8d8bea7e2c7fc9288fd3a197aca889123fa7283e44492b7e0197853b0
EOF
)"
termux_download "https://github.com/MrAdityaAlok/ghc-cross-tools/releases/download/ghc-v${TERMUX_GHC_VERSION}/ghc-cross-bin-${TERMUX_GHC_VERSION}-${TERMUX_ARCH}.tar.xz" \
"${TERMUX_GHC_TAR}" \
"$(echo "${CHECKSUMS}" | grep -w "${TERMUX_ARCH}" | cut -d ':' -f 2)"
(
if tar -tf "${TERMUX_GHC_TAR}" | grep "^./$" >/dev/null; then
# Strip prefixed ./, to avoid possible
# permission errors from tar
tar -xf "${TERMUX_GHC_TAR}" --strip-components=1 \
--no-overwrite-dir -C /
else
tar -xf "${TERMUX_GHC_TAR}" --no-overwrite-dir -C /
fi
)
local _HOST="${TERMUX_HOST_PLATFORM}"
[ "${TERMUX_ARCH}" = "arm" ] && _HOST="armv7a-linux-androideabi"
mkdir -p "${GHC_BIN}"
for tool in ghc ghc-pkg hsc2hs hp2ps; do
ln -sf "${TERMUX_PREFIX}/bin/${_HOST}-${tool}" "${GHC_BIN}/termux-${tool}"
done
for f in "${TERMUX_PREFIX}"/bin/"${_HOST}"-*; do
sed -i -e "s|^#!${TERMUX_PREFIX}/bin/sh|#!/usr/bin/sh|" \
-e "s|${_HOST}-ghc-${TERMUX_GHC_VERSION}|ghc-${TERMUX_GHC_VERSION}|g" \
"$f"
done
# GHC ships with old version, we use our own.
termux-ghc-pkg unregister Cabal
rm "${TERMUX_GHC_TAR}"
else
if [[ "$TERMUX_MAIN_PACKAGE_FORMAT" = "debian" && "$(dpkg-query -W -f '${db:Status-Status}\n' ghc 2>/dev/null)" != "installed" ]] ||
[[ "$TERMUX_MAIN_PACKAGE_FORMAT" = "pacman" && ! "$(pacman -Q ghc 2>/dev/null)" ]]; then
echo "Package 'ghc' is not installed."
exit 1
else
export PATH="${ON_DEVICE_GHC_BIN}:${PATH}"
[ -d "${ON_DEVICE_GHC_BIN}" ] && return
local ON_DEVICE_GHC_BIN="${TERMUX_COMMON_CACHEDIR}/${GHC_PREFIX}-runtime"
mkdir -p "${ON_DEVICE_GHC_BIN}"
for tool in ghc ghc-pkg hsc2hs hp2ps; do
ln -sf "${TERMUX_PREFIX}/bin/${tool}" "${ON_DEVICE_GHC_BIN}/termux-${tool}"
done
fi
fi
}

View File

@ -0,0 +1,47 @@
# Utility script to setup jailbreak-cabal script. It is used by haskell build system to remove version
# constraints in cabal files.
termux_setup_jailbreak_cabal() {
if [ "${TERMUX_ON_DEVICE_BUILD}" = "false" ]; then
local TERMUX_JAILBREAK_VERSION=1.3.5
local TERMUX_JAILBREAK_TMPDIR="${TERMUX_COMMON_CACHEDIR}/jailbreak-cabal-${TERMUX_JAILBREAK_VERSION}"
local TERMUX_JAILBREAK_TAR="${TERMUX_JAILBREAK_TMPDIR}.tar.gz"
local TERMUX_JAILBREAK_RUNTIME_FOLDER
if [ "${TERMUX_PACKAGES_OFFLINE-false}" = "true" ]; then
TERMUX_JAILBREAK_RUNTIME_FOLDER="${TERMUX_SCRIPTDIR}/build-tools/jailbreak-cabal-${TERMUX_JAILBREAK_VERSION}-runtime"
else
TERMUX_JAILBREAK_RUNTIME_FOLDER="${TERMUX_COMMON_CACHEDIR}/jailbreak-cabal-${TERMUX_JAILBREAK_VERSION}-runtime"
fi
export PATH="${TERMUX_JAILBREAK_RUNTIME_FOLDER}/bin:${PATH}"
[ -d "${TERMUX_JAILBREAK_RUNTIME_FOLDER}" ] && return
termux_download "https://hackage.haskell.org/package/jailbreak-cabal-${TERMUX_JAILBREAK_VERSION}/jailbreak-cabal-${TERMUX_JAILBREAK_VERSION}.tar.gz" \
"${TERMUX_JAILBREAK_TAR}" \
"8d1fce7dd9b755367f8236d91c94c5bb212a5fea9d8bc32696774cff5e7f4188"
mkdir -p "${TERMUX_JAILBREAK_RUNTIME_FOLDER}" "${TERMUX_JAILBREAK_TMPDIR}"
tar xf "${TERMUX_JAILBREAK_TAR}" -C "${TERMUX_JAILBREAK_TMPDIR}" --strip-components=1
(
cd "${TERMUX_JAILBREAK_TMPDIR}"
termux_setup_ghc
runhaskell Setup configure \
--prefix="${TERMUX_JAILBREAK_RUNTIME_FOLDER}" \
--enable-shared \
--enable-executable-dynamic \
--ghc-options=-dynamic
runhaskell Setup build
runhaskell Setup install
)
rm "${TERMUX_JAILBREAK_TAR}"
rm -Rf "${TERMUX_JAILBREAK_TMPDIR}"
else
if [[ "$TERMUX_MAIN_PACKAGE_FORMAT" = "debian" && "$(dpkg-query -W -f '${db:Status-Status}\n' jailbreak-cabal 2>/dev/null)" != "installed" ]] ||
[[ "$TERMUX_MAIN_PACKAGE_FORMAT" = "pacman" && ! "$(pacman -Q jailbreak-cabal 2>/dev/null)" ]]; then
echo "Package 'jailbreak-cabal' is not installed."
exit 1
fi
fi
}

View File

@ -6,21 +6,34 @@ termux_step_get_dependencies() {
# When doing build on device, ensure that apt lists are up-to-date.
if [ "$TERMUX_ON_DEVICE_BUILD" = "true" ]; then
case "$TERMUX_MAIN_PACKAGE_FORMAT" in
"debian") apt update;;
"pacman") pacman -Sy;;
"debian") apt update ;;
"pacman") pacman -Sy ;;
esac
fi
# We use this variable to track what haskell packages are required by this build,
# which needs to be registered in the cross ghc package database.
declare -a HASKELL_PKGS_TO_REGISTER=()
# We do not allow setting up ghc cross compiler manually as they need to be installed in $TERMUX_PREFIX,
# which should be done before timestamp creation.
local IS_GHC_REQUIRED=false # Whether we need to setup GHC cross compiler.
# Download dependencies
while read PKG PKG_DIR; do
if [ -z $PKG ]; then
continue
elif [ "$PKG" = "ERROR" ]; then
termux_error_exit "Obtaining buildorder failed"
elif [ "$PKG" = "ghc" ] || [ "$PKG" = "ghc-libs" ] || [ "$PKG" = "ghc-libs-static" ]; then
IS_GHC_REQUIRED=true
fi
# Store haskell packages to register them in the cross ghc package database later.
if [ "${PKG/haskell-/}" != "$PKG" ]; then
HASKELL_PKGS_TO_REGISTER+=("${PKG}")
fi
# llvm doesn't build if ndk-sysroot is installed:
if [ "$PKG" = "ndk-sysroot" ]; then continue; fi
read DEP_ARCH DEP_VERSION DEP_VERSION_PAC <<< $(termux_extract_dep_info $PKG "${PKG_DIR}")
read DEP_ARCH DEP_VERSION DEP_VERSION_PAC <<<$(termux_extract_dep_info $PKG "${PKG_DIR}")
if [ ! "$TERMUX_QUIET_BUILD" = true ]; then
echo "Downloading dependency $PKG@$DEP_VERSION if necessary..."
@ -44,7 +57,7 @@ termux_step_get_dependencies() {
(
cd $TERMUX_COMMON_CACHEDIR-$DEP_ARCH
ar x ${PKG}_${DEP_VERSION}_${DEP_ARCH}.deb data.tar.xz
if tar -tf data.tar.xz|grep "^./$">/dev/null; then
if tar -tf data.tar.xz | grep "^./$" >/dev/null; then
# Strip prefixed ./, to avoid possible
# permission errors from tar
tar -xf data.tar.xz --strip-components=1 \
@ -56,8 +69,8 @@ termux_step_get_dependencies() {
fi
mkdir -p $TERMUX_BUILT_PACKAGES_DIRECTORY
echo "$DEP_VERSION" > "$TERMUX_BUILT_PACKAGES_DIRECTORY/$PKG"
done<<<$(./scripts/buildorder.py -i "$TERMUX_PKG_BUILDER_DIR" $TERMUX_PACKAGES_DIRECTORIES || echo "ERROR")
echo "$DEP_VERSION" >"$TERMUX_BUILT_PACKAGES_DIRECTORY/$PKG"
done <<<$(./scripts/buildorder.py -i "$TERMUX_PKG_BUILDER_DIR" $TERMUX_PACKAGES_DIRECTORIES || echo "ERROR")
elif [ "$TERMUX_SKIP_DEPCHECK" = false ] && [ "$TERMUX_INSTALL_DEPS" = false ] && [ "$TERMUX_PKG_METAPACKAGE" = "false" ]; then
# Build dependencies
while read PKG PKG_DIR; do
@ -69,6 +82,17 @@ termux_step_get_dependencies() {
echo "Building dependency $PKG if necessary..."
# Built dependencies are put in the default TERMUX_OUTPUT_DIR instead of the specified one
TERMUX_BUILD_IGNORE_LOCK=true ./build-package.sh -s --format $TERMUX_PACKAGE_FORMAT "${PKG_DIR}"
done<<<$(./scripts/buildorder.py "$TERMUX_PKG_BUILDER_DIR" $TERMUX_PACKAGES_DIRECTORIES || echo "ERROR")
done <<<$(./scripts/buildorder.py "$TERMUX_PKG_BUILDER_DIR" $TERMUX_PACKAGES_DIRECTORIES || echo "ERROR")
fi
if [ "${IS_GHC_REQUIRED}" = true ]; then
termux_setup_ghc_cross_compiler
fi
# Register haskell packages either installed or built, which are required by this build, with cross ghc.
for pkg in "${HASKELL_PKGS_TO_REGISTER[@]}"; do
echo "${pkg} is an haskell package, registering it with ghc-pkg..."
sed "s|${TERMUX_PREFIX}/bin/ghc-pkg|$(command -v termux-ghc-pkg)|g" \
"${TERMUX_PREFIX}/share/haskell/register/${pkg}.sh" | sh
termux-ghc-pkg recache
done
}

View File

@ -8,7 +8,9 @@ termux_step_make() {
if test -f build.ninja; then
ninja -w dupbuild=warn -j $TERMUX_MAKE_PROCESSES
elif ls ./*akefile &> /dev/null || [ ! -z "$TERMUX_PKG_EXTRA_MAKE_ARGS" ]; then
elif ls ./*.cabal &>/dev/null; then
runhaskell Setup -j$TERMUX_MAKE_PROCESSES build
elif ls ./*akefile &>/dev/null || [ ! -z "$TERMUX_PKG_EXTRA_MAKE_ARGS" ]; then
if [ -z "$TERMUX_PKG_EXTRA_MAKE_ARGS" ]; then
make -j $TERMUX_MAKE_PROCESSES $QUIET_BUILD
else

View File

@ -3,7 +3,27 @@ termux_step_make_install() {
if test -f build.ninja; then
ninja -w dupbuild=warn -j $TERMUX_MAKE_PROCESSES install
elif ls ./*akefile &> /dev/null || [ -n "$TERMUX_PKG_EXTRA_MAKE_ARGS" ]; then
elif ls ./*.cabal &>/dev/null; then
runhaskell Setup copy
if [ "${TERMUX_PKG_IS_HASKELL_LIB}" = true ]; then
runhaskell Setup register --gen-script
runhaskell Setup unregister --gen-script
install -Dm744 register.sh "${TERMUX_PREFIX}"/share/haskell/register/"${TERMUX_PKG_NAME}".sh
install -Dm744 unregister.sh "${TERMUX_PREFIX}"/share/haskell/unregister/"${TERMUX_PKG_NAME}".sh
sed -i -r -e "s|$(command -v termux-ghc-pkg)|${TERMUX_PREFIX}/bin/ghc-pkg|g" \
-e "s|ghc-pkg.*update[^ ]* |&'--force' |" \
-e "s|export PATH=.*||g" \
"${TERMUX_PREFIX}"/share/haskell/register/"${TERMUX_PKG_NAME}".sh
sed -i -r -e "s|$(command -v termux-ghc-pkg)|${TERMUX_PREFIX}/bin/ghc-pkg|g" \
-e "s|export PATH=.*||g" \
-e "s|ghc-pkg.*unregister[^ ]* |&'--force' |" \
"${TERMUX_PREFIX}"/share/haskell/unregister/"${TERMUX_PKG_NAME}".sh
fi
elif ls ./*akefile &>/dev/null || [ -n "$TERMUX_PKG_EXTRA_MAKE_ARGS" ]; then
: "${TERMUX_PKG_MAKE_INSTALL_TARGET:="install"}"
# Some packages have problem with parallell install, and it does not buy much, so use -j 1.
if [ -z "$TERMUX_PKG_EXTRA_MAKE_ARGS" ]; then