Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions recipes/ghc-cross-compilers/activate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash

if [[ "$(uname)" == "Linux" ]] && [[ "$(uname -m)" == "x86_64" ]]; then
aarch64-conda-linux-gnu-ghc-pkg recache
fi
56 changes: 56 additions & 0 deletions recipes/ghc-cross-compilers/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/usr/bin/env bash
set -eu

# Set up binary directory
mkdir -p binary/bin _logs

# Create bash completion
mkdir -p "${PREFIX}"/etc/bash_completion.d

export MergeObjsCmd=${LD_GOLD:-${LD}}
export M4=${BUILD_PREFIX}/bin/m4
export PYTHON=${BUILD_PREFIX}/bin/python
export PATH=${BUILD_PREFIX}/ghc-bootstrap/bin${PATH:+:}${PATH:-}

"${RECIPE_DIR}"/building/build-"${target_platform}.sh"

# Create bash completion
mkdir -p "${PREFIX}"/etc/bash_completion.d
cp utils/completion/ghc.bash "${PREFIX}"/etc/bash_completion.d/ghc

# Clean up package cache
# Does this allow building Hello with inbedded HS libs and prevent segfault on linux and 4GB reloc on osx?
# find "${PREFIX}"/lib/*ghc-"${PKG_VERSION}" -name '*inplace.a' -delete
find "${PREFIX}"/lib/*ghc-"${PKG_VERSION}" -name '*_p.a' -delete
find "${PREFIX}"/lib/*ghc-"${PKG_VERSION}" -name '*.p_o' -delete

# Clean up package cache
rm -f "${PREFIX}"/lib/*ghc-"${PKG_VERSION}"/lib/package.conf.d/package.cache
rm -f "${PREFIX}"/lib/*ghc-"${PKG_VERSION}"/lib/package.conf.d/package.cache.lock

mkdir -p "${PREFIX}/etc/conda/activate.d"
cp "${RECIPE_DIR}/activate.sh" "${PREFIX}/etc/conda/activate.d/${PKG_NAME}_activate.sh"

# Cleanup potential hard-coded build env paths
if [[ -f "${PREFIX}"/lib/ghc-"${PKG_VERSION}"/lib/settings ]]; then
perl -pi -e 's#($ENV{BUILD_PREFIX}|$ENV{PREFIX})/bin/##g' "${PREFIX}"/lib/ghc-"${PKG_VERSION}"/lib/settings
fi

# Find all the .dylib libs with the '-ghc9.12.2' extension and link them to non-'-ghc9.12.2'
find "${PREFIX}/lib" -name "*-ghc${PKG_VERSION}.dylib" -o -name "*-ghc${PKG_VERSION}.so" | while read -r lib; do
base_lib="${lib//-ghc${PKG_VERSION}./.}"
if [[ ! -e "$base_lib" ]]; then
ln -s "$(basename "$lib")" "$base_lib"
fi
done

# Add package licenses
arch="-${target_platform#*-}"
arch="${arch//-64/-x86_64}"
arch="${arch#*-}"
arch="${arch//arm64/aarch64}"
pushd "${PREFIX}/share/doc/${arch}-${target_platform%%-*}-ghc-${PKG_VERSION}-inplace" || true
for file in */LICENSE; do
cp "${file///-}" "${SRC_DIR}"/license_files
done
popd
198 changes: 198 additions & 0 deletions recipes/ghc-cross-compilers/building/build-linux-64.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
#!/usr/bin/env bash
set -eu

_log_index=0

source "${RECIPE_DIR}"/building/common.sh

# Update cabal package database
run_and_log "cabal-update" cabal v2-update

_hadrian_build=("${SRC_DIR}"/hadrian/build "-j${CPU_COUNT}")

# Create aarch64 environment and get library paths
echo "Creating aarch64 environment for cross-compilation libraries..."
conda create -y \
-n aarch64_env \
--platform linux-aarch64 \
-c conda-forge \
gmp \
libffi \
libiconv \
ncurses

sleep 10

# Get the environment path and set up library paths
AARCH64_ENV_PATH=$(conda info --envs | grep aarch64_env | awk '{print $2}')
export AARCH64_LIB_DIR="${AARCH64_ENV_PATH}/lib"
export AARCH64_INCLUDE_DIR="${AARCH64_ENV_PATH}/include"

AARCH64_CFLAGS=$(echo "$CFLAGS" | sed 's/-mtune=[^ ]*/-mtune=generic/g' | sed 's/ */ /g' | sed 's/^ *//' | sed 's/ *$//')
AARCH64_CFLAGS=$(echo "$AARCH64_CFLAGS" | sed 's/-march=[^ ]*/-march=armv8-a/g' | sed 's/ */ /g' | sed 's/^ *//' | sed 's/ *$//')
AARCH64_CXXFLAGS=$(echo "$CXXFLAGS" | sed 's/-mtune=[^ ]*/-mtune=generic/g' | sed 's/ */ /g' | sed 's/^ *//' | sed 's/ *$//')
AARCH64_CXXFLAGS=$(echo "$AARCH64_CXXFLAGS" | sed 's/-march=[^ ]*/-march=armv8-a/g' | sed 's/ */ /g' | sed 's/^ *//' | sed 's/ *$//')
AARCH64_CPPFLAGS=$(echo "$CPPFLAGS" | sed 's/-mtune=[^ ]*/-mtune=generic/g' | sed 's/ */ /g' | sed 's/^ *//' | sed 's/ *$//')
AARCH64_CPPFLAGS=$(echo "$AARCH64_CPPFLAGS" | sed 's/-march=[^ ]*/-march=armv8-a/g' | sed 's/ */ /g' | sed 's/^ *//' | sed 's/ *$//')

echo "aarch64 libraries located at: ${AARCH64_LIB_DIR}"
echo "aarch64 headers located at: ${AARCH64_INCLUDE_DIR}"

# Configure and build GHC
SYSTEM_CONFIG=(
--build="x86_64-conda-linux-gnu"
--host="x86_64-conda-linux-gnu"
--target="aarch64-unknown-linux"
--prefix="${PREFIX}"
)

CONFIGURE_ARGS=(
--enable-ignore-build-platform-mismatch=yes
--disable-numa
--with-system-libffi=yes
--with-curses-includes="${AARCH64_INCLUDE_DIR}"
--with-curses-libraries="${AARCH64_LIB_DIR}"
--with-ffi-includes="${AARCH64_INCLUDE_DIR}"
--with-ffi-libraries="${AARCH64_LIB_DIR}"
--with-gmp-includes="${AARCH64_INCLUDE_DIR}"
--with-gmp-libraries="${AARCH64_LIB_DIR}"
--with-iconv-includes="${AARCH64_INCLUDE_DIR}"
--with-iconv-libraries="${AARCH64_LIB_DIR}"
)

# Set up aarch64 cross-compilation toolchain
MergeObjsCmd=aarch64-conda-linux-gnu-ld.gold \
AR=aarch64-conda-linux-gnu-ar \
AS=aarch64-conda-linux-gnu-as \
CC=aarch64-conda-linux-gnu-clang \
CXX=aarch64-conda-linux-gnu-clang++ \
LD=aarch64-conda-linux-gnu-ld \
NM=aarch64-conda-linux-gnu-nm \
OBJDUMP=aarch64-conda-linux-gnu-objdump \
RANLIB=aarch64-conda-linux-gnu-ranlib \
CFLAGS="${AARCH64_CFLAGS}" \
CXXFLAGS="${AARCH64_CXXFLAGS}" \
run_and_log "ghc-configure" bash configure "${SYSTEM_CONFIG[@]}" "${CONFIGURE_ARGS[@]}"

# Patch host/target configurations
perl -pi -e 's#"--target=[\w-]+"#"--target=x86_64-unknown-linux","--sysroot=$ENV{BUILD_PREFIX}/x86_64-conda-linux-gnu/sysroot"#' "${SRC_DIR}"/hadrian/cfg/default.host.target
perl -pi -e 's/aarch64/x86_64/;s/ArchAArch64/ArchX86_64/' "${SRC_DIR}"/hadrian/cfg/default.host.target

perl -pi -e 's#"--target=[\w-]+"#"--target=aarch64-unknown-linux","--sysroot=$ENV{BUILD_PREFIX}/aarch64-conda-linux-gnu/sysroot"#' "${SRC_DIR}"/hadrian/cfg/default.target
perl -pi -e 's#"--target=[\w-]+"#"--target=aarch64-unknown-linux","--sysroot=$ENV{BUILD_PREFIX}/aarch64-conda-linux-gnu/sysroot"#' "${SRC_DIR}"/hadrian/cfg/default.target
# perl -pi -e 's#(settings-llvm-as-command = )([\w-]+)#\1"\2 --target=x86_64-unknown-linux"#' "${SRC_DIR}"/hadrian/cfg/system.config

perl -pi -e 's#(settings-llvm-as-command = )([\w-]+)#\1aarch64-conda-linux-gnu-as#' "${SRC_DIR}"/hadrian/cfg/system.config

# Create UserSettings.hs for Stage1 cross-compiler build
cat ${RECIPE_DIR}/cross-UserSettings.hs > hadrian/UserSettings.hs

mkdir -p ${SRC_DIR}/_cross-compiler
run_and_log "binary-dist" "${_hadrian_build[@]}" binary-dist --prefix="${SRC_DIR}/_cross-compiler" --docs=none --progress-info=none --flavour=perf

export MergeObjsCmd=aarch64-conda-linux-gnu-ld.gold
export AR=aarch64-conda-linux-gnu-ar
export AS=aarch64-conda-linux-gnu-as
export CC=aarch64-conda-linux-gnu-clang
export CXX=aarch64-conda-linux-gnu-clang++
export LD=aarch64-conda-linux-gnu-ld
export LD_GOLD=aarch64-conda-linux-gnu-ld.gold
export NM=aarch64-conda-linux-gnu-nm
export RANLIB=aarch64-conda-linux-gnu-ranlib

export build_alias=x86_64-conda-linux-gnu
export host_alias=x86_64-conda-linux-gnu
export target_alias=aarch64-unknown-linux

# Clear x86_64 flags that break aarch64 cross-compiler and set correct sysroot
export CFLAGS="${AARCH64_CFLAGS} --sysroot=${BUILD_PREFIX}/aarch64-conda-linux-gnu/sysroot"
export CXXFLAGS="${AARCH64_CXXFLAGS} --sysroot=${BUILD_PREFIX}/aarch64-conda-linux-gnu/sysroot"
export CPPFLAGS="${AARCH64_CPPFLAGS}"
export LDFLAGS="--sysroot=${BUILD_PREFIX}/aarch64-conda-linux-gnu/sysroot"

run_and_log "cross-install" "${_hadrian_build[@]}" install --prefix="${SRC_DIR}/_cross-compiler" --flavour=perf --docs=none

# Create aarch64-prefixed binaries for the cross-compiler
pushd "${SRC_DIR}"/_cross-compiler
# Rename the cross-compiler links to binaries to aarch64-conda-linux-gnu-* format
for prog in $(find bin -name "aarch64-unknown-linux-*"); do
if [[ "${prog}" != *"-${PKG_VERSION}" ]]; then
mv "${prog}" $(echo "${prog}" | sed 's/aarch64-unknown-linux-/aarch64-conda-linux-gnu-/')
fi
done

# Just to be safe with the native naming
rm -rf share/ghc-"${PKG_VERSION}"
popd

# Patch the settings file AFTER moving to PREFIX so paths are correct
# Move to PREFIX first
(cd "${SRC_DIR}/_cross-compiler" && tar cf - ./* | (cd "${PREFIX}" && tar xf -) )

settings_file=$(find "${PREFIX}" -name settings -type f | grep aarch64 | head -1)
echo "Fixing settings file: $settings_file"

# We enforce prioritizing the sysroot for self-consistently finding the libraries
if [[ -f "$settings_file" ]]; then
# The settings already have the right compiler and basic sysroot, just add include path override
perl -i -pe 's#("C compiler flags", ")([^"]*)"#\1\2 -isysroot \$topdir/../../../aarch64-conda-linux-gnu/sysroot"#g' "${settings_file}"
perl -i -pe 's#("C\+\+ compiler flags", ")([^"]*)"#\1\2 -isysroot \$topdir/../../../aarch64-conda-linux-gnu/sysroot"#g' "${settings_file}"
perl -i -pe 's#("CPP compiler flags", ")([^"]*)"#\1\2 -isysroot \$topdir/../../../aarch64-conda-linux-gnu/sysroot"#g' "${settings_file}"

perl -i -pe 's#("C compiler link flags", ")([^"]*)"#\1\2 -L\$topdir/../../../lib -Wl,-rpath,\$topdir/../../../lib"#g' "${settings_file}"

perl -i -pe 's#("LLVM llvm-as command", ")([^"]*)"#\1aarch64-conda-linux-gnu-clang"#g' "${settings_file}"

echo "Settings file patched successfully"
else
echo "Warning: Settings file not found at $settings_file"
fi

# Fix hardcoded paths in wrapper scripts
echo "Fixing wrapper script paths..."
find "${PREFIX}/bin" -name "*ghc*" -type f | grep "aarch64" | while read -r wrapper; do
if grep -q -E "(exedir=|includedir=|libdir=|docdir=|mandir=|datadir=)" "$wrapper"; then
echo "Fixing paths in: $wrapper"
# Replace all hardcoded absolute paths with relative paths (POSIX sh compatible)
perl -i -pe 's#exedir="[^"]*"#exedir="\$( cd "\$( dirname "\$0" )/../lib/aarch64-unknown-linux-ghc-'"${PKG_VERSION}"'/bin" \&\& pwd )"#g' "$wrapper"
perl -i -pe 's#executablename="[^"]*"#executablename="\$exedir/\$exeprog"#g' "$wrapper"
perl -i -pe 's#bindir="[^"]*"#bindir="\$( cd "\$( dirname "\$0" )" \&\& pwd )"#g' "$wrapper"
perl -i -pe 's#libdir="[^"]*"#libdir="\$( cd "\$( dirname "\$0" )/../lib/aarch64-unknown-linux-ghc-'"${PKG_VERSION}"'/lib" \&\& pwd )"#g' "$wrapper"
perl -i -pe 's#includedir="[^"]*"#includedir="\$( cd "\$( dirname "\$0" )/../include" \&\& pwd )"#g' "$wrapper"
perl -i -pe 's#docdir="[^"]*"#docdir="\$( cd "\$( dirname "\$0" )/../share/doc/aarch64-unknown-linux-ghc-'"${PKG_VERSION}"'" \&\& pwd )"#g' "$wrapper"
perl -i -pe 's#mandir="[^"]*"#mandir="\$( cd "\$( dirname "\$0" )/../share/man" \&\& pwd )"#g' "$wrapper"
perl -i -pe 's#datadir="[^"]*"#datadir="\$( cd "\$( dirname "\$0" )/../share" \&\& pwd )"#g' "$wrapper"
echo "Fixed: $wrapper"
fi
done

# We need to map the PREFIX environment sysroot
mkdir -p "${PREFIX}"/aarch64-conda-linux-gnu && ln -s "${BUILD_PREFIX}"/aarch64-conda-linux-gnu/sysroot "${PREFIX}"/aarch64-conda-linux-gnu/sysroot

# Enforce sysroot usage for interdependent system lib
# Solves librt.so needing libpthreads.so but finding the /lib64
# instead of the self-consistent sysrrot
sysroot_lib64="${PREFIX}/aarch64-conda-linux-gnu/sysroot/lib64"
sysroot_usr_lib64="${PREFIX}/aarch64-conda-linux-gnu/sysroot/usr/lib64"
conda_lib="${PREFIX}/lib"

echo "Patching binaries and libraries"
{
find "${PREFIX}"/bin -type f -executable | grep "aarch64" | grep "ghc"
find "${PREFIX}"/lib -name "*.so*" | grep "aarch64" | grep "ghc"
} | while read -r binary; do
if file "$binary" | grep -q "ELF"; then
current_rpath=$(patchelf --print-rpath "$binary" 2>/dev/null || echo "")
_sysroot_lib64="$(calculate_origin_rpath "$binary" "$sysroot_lib64")"
_sysroot_usr_lib64="$(calculate_origin_rpath "$binary" "$sysroot_usr_lib64")"
_conda_lib="$(calculate_origin_rpath "$binary" "$conda_lib")"
new_rpath="${_sysroot_lib64}:${_sysroot_usr_lib64}:${_conda_lib}"
if [[ -n "$current_rpath" ]]; then
new_rpath="${new_rpath}:${current_rpath}"
fi
patchelf --set-rpath "$new_rpath" "$binary" 2>/dev/null && echo -n "."
fi
done
echo " done"

rm -rf "${PREFIX}"/aarch64-conda-linux-gnu
97 changes: 97 additions & 0 deletions recipes/ghc-cross-compilers/building/build-linux-aarch64.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#!/usr/bin/env bash
set -eu

_log_index=0

source "${RECIPE_DIR}"/building/common.sh

_build_alias=${build_alias}
_host_alias=${host_alias}
_ghc_host="x86_64-conda-linux-gnu"

export build_alias="${_ghc_host}"
export host_alias="${_ghc_host}"
export BUILD=${build_alias}
export HOST=${host_alias}

# Update cabal package database
run_and_log "cabal-update" cabal v2-update

_hadrian_build=("${SRC_DIR}"/hadrian/build "-j${CPU_COUNT}")

# Configure and build GHC
SYSTEM_CONFIG=(
--build="x86_64-conda-linux-gnu"
--host="x86_64-conda-linux-gnu"
--target="aarch64-conda-linux-gnu"
--prefix="${PREFIX}"
)

CONFIGURE_ARGS=(
--enable-ignore-build-platform-mismatch=yes
--disable-numa
--with-system-libffi=yes
--with-curses-includes="${PREFIX}"/include
--with-curses-libraries="${PREFIX}"/lib
--with-ffi-includes="${PREFIX}"/include
--with-ffi-libraries="${PREFIX}"/lib
--with-gmp-includes="${PREFIX}"/include
--with-gmp-libraries="${PREFIX}"/lib
--with-iconv-includes="${PREFIX}"/include
--with-iconv-libraries="${PREFIX}"/lib
)

# env
# cat $(find ${BUILD_PREFIX} -name settings -type f)

MergeObjsCmd=aarch64-conda-linux-gnu-ld.gold \
AR=aarch64-conda-linux-gnu-ar \
AS=aarch64-conda-linux-gnu-as \
CC=aarch64-conda-linux-gnu-clang \
CXX=aarch64-conda-linux-gnu-clang++ \
NM=aarch64-conda-linux-gnu-nm \
RANLIB=aarch64-conda-linux-gnu-ranlib \
run_and_log "ghc-configure" bash configure "${SYSTEM_CONFIG[@]}" "${CONFIGURE_ARGS[@]}"

# Fix host configuration to use x86_64, target aarch64
perl -pi -e 's#"--target=[\w-]+"#"--target=x86_64-unknown-linux","--sysroot=$ENV{BUILD_PREFIX}/x86_64-conda-linux-gnu/sysroot"#' "${SRC_DIR}"/hadrian/cfg/default.host.target
perl -pi -e 's/aarch64/x86_64/;s/ArchAArch64/ArchX86_64/' "${SRC_DIR}"/hadrian/cfg/default.host.target
perl -pi -e 's#"--target=[\w-]+"#"--target=aarch64-unknown-linux","--sysroot=$ENV{BUILD_PREFIX}/aarch64-conda-linux-gnu/sysroot"#' "${SRC_DIR}"/hadrian/cfg/default.target

run_and_log "stage1_exe" "${_hadrian_build[@]}" stage1:exe:ghc-bin --flavour=release --docs=none --progress-info=none
perl -pi -e 's#($ENV{BUILD_PREFIX}|$ENV{PREFIX})/bin/##' "${SRC_DIR}"/_build/stage0/lib/settings

# GHC build ghc-pkg with '-fno-use-rpaths' but it requires libiconv.so.2
# _build/stage1/bin/ghc-pkg: error while loading shared libraries: libiconv.so.2
export LD_PRELOAD="${BUILD_PREFIX}/lib/libiconv.so.2 ${BUILD_PREFIX}/lib/libgmp.so.10 ${BUILD_PREFIX}/lib/libffi.so.8 ${BUILD_PREFIX}/lib/libtinfow.so.6 ${BUILD_PREFIX}/lib/libtinfo.so.6 ${LD_PRELOAD:-}"
run_and_log "bindist" "${_hadrian_build[@]}" binary-dist --prefix="${PREFIX}" --flavour=release --docs=none --progress-info=none

# Now manually install from the bindist with correct configure arguments
BINDIST_DIR=$(find "${SRC_DIR}"/_build/bindist -name "ghc-*-aarch64-conda-linux-gnu" -type d | head -1)
if [[ -n "${BINDIST_DIR}" ]]; then
pushd "${BINDIST_DIR}"

# Configure the binary distribution with proper cross-compilation settings
./configure --prefix="${PREFIX}" --build=x86_64-conda-linux-gnu --host=x86_64-conda-linux-gnu --target=aarch64-conda-linux-gnu

# Install
make install

popd
else
echo "Error: Could not find binary distribution directory"
exit 1
fi

# Create links of aarch64-conda-linux-gnu-xxx to xxx
pushd "${PREFIX}"/bin
for bin in aarch64-conda-linux-gnu-*; do
ln -s "${bin}" "${bin#aarch64-conda-linux-gnu-}"
done
popd

if [[ -d "${PREFIX}"/lib/aarch64-conda-linux-gnu-ghc-"${PKG_VERSION}" ]]; then
# $PREFIX/lib/aarch64-conda-linux-gnu-ghc-9.12.2 -> $PREFIX/lib/ghc-9.12.2
mv "${PREFIX}"/lib/aarch64-conda-linux-gnu-ghc-"${PKG_VERSION}" "${PREFIX}"/lib/ghc-"${PKG_VERSION}"
ln -sf "${PREFIX}"/lib/ghc-"${PKG_VERSION}" "${PREFIX}"/lib/aarch64-conda-linux-gnu-ghc-"${PKG_VERSION}"
fi
Loading
Loading