#!/usr/bin/env bash
# $Id: CrossCompile 82 2026-08-15 11:13:33Z peter $
#
# Copyright (C) 2026 Peter Felecan
# Assisted by Claude Sonnet 5 (Anthropic)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# CrossCompile — cross-compilation driver for svah.
#
# Builds libsvah, svah, and svahsim for an ARM target from an amd64
# Debian host. The build is placed in a target-specific subdirectory.
#
# Usage:
#   CrossCompile --target armv7 [--readline] [--clean]
#   CrossCompile --target aarch64 [--readline] [--clean]
#   CrossCompile --target rpi1 [--readline] [--clean]
#
# Targets:
#   armv7    RPi 2, RPi 3 (32-bit), Debian arm-linux-gnueabihf
#   aarch64  RPi 3/4/5 (64-bit), Debian aarch64-linux-gnu
#   rpi1     RPi 1, Pi Foundation toolchain (must be in PATH)
#
# Options:
#   --readline   Link readline (requires cross-compiled libreadline)
#   --clean      Run make maintainer-clean before configuring
#   -h, --help   Print this help and exit
#
# Exit status:
#   0  — success
#   1  — error

set -e
trap 'echo "CrossCompile: unexpected error on line ${LINENO}" >&2' ERR

# ------------------------------------------------------------------ #
# Defaults                                                             #
# ------------------------------------------------------------------ #

TARGET=""
WITH_READLINE="no"
CLEAN="no"
MIN_GLIBC=""
FORCE="no"

# ------------------------------------------------------------------ #
# Usage                                                                #
# ------------------------------------------------------------------ #

usage()
{
    cat << USAGE
Usage: ${0##*/} --target armv7|aarch64|rpi1 [--readline] [--clean]

Targets:
  armv7    RPi 2 / RPi 3 32-bit  (Debian arm-linux-gnueabihf)
  aarch64  RPi 3/4/5 64-bit      (Debian aarch64-linux-gnu)
  rpi1     RPi 1 ARMv6            (Pi Foundation toolchain in PATH)

Options:
  --readline          Enable readline in svahsim (requires cross-compiled libreadline)
  --clean             Run make maintainer-clean and re-bootstrap before configuring
  --min-glibc M.N     Check that build system GLIBC <= M.N (target minimum)
  --force             Override GLIBC version mismatch warning
  -h, --help          Print this help and exit

Required packages on Debian host:
  armv7:   sudo apt install gcc-arm-linux-gnueabihf binutils-arm-linux-gnueabihf
  aarch64: sudo apt install gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu
  rpi1:    Pi Foundation toolchain — see DevelopmentStandard.org
USAGE
}

# ------------------------------------------------------------------ #
# Option parsing                                                       #
# ------------------------------------------------------------------ #

ARGS=$(getopt -o h \
    --long target:,readline,clean,min-glibc:,force,help \
    -n "${0##*/}" -- "$@") || { usage; exit 1; }

eval set -- "${ARGS}"

while true
do
{
    case "${1}" in
        --target)   TARGET="${2}";       shift 2 ;;
        --readline) WITH_READLINE="yes"; shift ;;
        --clean)    CLEAN="yes";         shift ;;
        --min-glibc) MIN_GLIBC="${2}";   shift 2 ;;
        --force)    FORCE="yes";         shift ;;
        -h|--help)  usage;               exit 0 ;;
        --)         shift;               break ;;
        *)          usage;               exit 1 ;;
    esac
}
done

if [ -z "${TARGET}" ]
then
    echo "${0##*/}: --target is required" >&2
    usage
    exit 1
fi

# ------------------------------------------------------------------ #
# Target configuration                                                 #
# ------------------------------------------------------------------ #

case "${TARGET}" in
    armv7)
        HOST_TRIPLE="arm-linux-gnueabihf"
        BUILD_DIR="build-armv7"
        CC="${HOST_TRIPLE}-gcc"
        AR="${HOST_TRIPLE}-ar"
        RANLIB="${HOST_TRIPLE}-ranlib"
        STRIP="${HOST_TRIPLE}-strip"
        ARCH_NOTE="ARMv7 (RPi 2 / RPi 3 32-bit)"
        ;;
    aarch64)
        HOST_TRIPLE="aarch64-linux-gnu"
        BUILD_DIR="build-aarch64"
        CC="${HOST_TRIPLE}-gcc"
        AR="${HOST_TRIPLE}-ar"
        RANLIB="${HOST_TRIPLE}-ranlib"
        STRIP="${HOST_TRIPLE}-strip"
        ARCH_NOTE="AArch64 (RPi 3/4/5 64-bit)"
        ;;
    rpi1)
        HOST_TRIPLE="arm-linux-gnueabihf"
        BUILD_DIR="build-rpi1"
        CC="${HOST_TRIPLE}-gcc"
        AR="${HOST_TRIPLE}-ar"
        RANLIB="${HOST_TRIPLE}-ranlib"
        STRIP="${HOST_TRIPLE}-strip"
        ARCH_NOTE="ARMv6 (RPi 1) — Pi Foundation toolchain"
        ;;
    *)
        echo "${0##*/}: unknown target '${TARGET}'" >&2
        usage
        exit 1
        ;;
esac

# ------------------------------------------------------------------ #
# Pre-flight: check cross-compiler is available                        #
# ------------------------------------------------------------------ #

if ! command -v "${CC}" > /dev/null 2>&1
then
    cat >&2 << MSG
${0##*/}: ${CC} not found.

Install on Debian:
  armv7:   sudo apt install gcc-arm-linux-gnueabihf
  aarch64: sudo apt install gcc-aarch64-linux-gnu
  rpi1:    add Pi Foundation toolchain to PATH

See DevelopmentStandard.org, section Cross-Compilation.
MSG
    exit 1
fi

echo "CrossCompile: target ${TARGET} (${ARCH_NOTE})"
echo "CrossCompile: compiler $(${CC} --version | head -1)"
echo "CrossCompile: build directory ${BUILD_DIR}"

# ------------------------------------------------------------------ #
# Clean and re-bootstrap if requested                                  #
# ------------------------------------------------------------------ #

if [ "${CLEAN}" = "yes" ]
then
    echo "CrossCompile: running make maintainer-clean"
    make maintainer-clean 2>/dev/null || true
    echo "CrossCompile: running bootstrap"
    ./bootstrap
fi

if [ ! -f configure ]
then
    echo "CrossCompile: configure not found, running bootstrap"
    ./bootstrap
fi

# ------------------------------------------------------------------ #
# Create build directory and configure                                 #
# ------------------------------------------------------------------ #

mkdir -p "${BUILD_DIR}"

CONFIGURE_ARGS=(
    --host="${HOST_TRIPLE}"
    --build=x86_64-linux-gnu
    CC="${CC}"
    AR="${AR}"
    RANLIB="${RANLIB}"
    STRIP="${STRIP}"
)

# ------------------------------------------------------------------ #
# GLIBC version compatibility check                                    #
# ------------------------------------------------------------------ #
# The build system's glibc version determines the minimum version
# required on the target. If the build system uses a newer glibc than
# the target, the binary will fail to load on the target.
#
# Example: Debian forky (build) uses GLIBC_2.38; Debian bookworm
# (target RPi) uses GLIBC_2.36. Cross-compiled binary from forky
# will not run on bookworm.
#
# Use --min-glibc M.N to verify the build system's glibc is <= M.N.

if [ -n "${MIN_GLIBC}" ]
then
    BUILD_GLIBC=$(ldd --version 2>/dev/null | awk 'NR==1{print $NF}')
    BUILD_MAJOR=$(echo "${BUILD_GLIBC}" | cut -d. -f1)
    BUILD_MINOR=$(echo "${BUILD_GLIBC}" | cut -d. -f2)
    MIN_MAJOR=$(echo "${MIN_GLIBC}" | cut -d. -f1)
    MIN_MINOR=$(echo "${MIN_GLIBC}" | cut -d. -f2)

    if [ "${BUILD_MAJOR}" -gt "${MIN_MAJOR}" ] || \
       { [ "${BUILD_MAJOR}" -eq "${MIN_MAJOR}" ] && \
         [ "${BUILD_MINOR}" -gt "${MIN_MINOR}" ]; }
    then
        echo ""
        echo "CrossCompile: WARNING — GLIBC version mismatch" >&2
        echo "  Build system GLIBC : ${BUILD_GLIBC}" >&2
        echo "  Target minimum     : ${MIN_GLIBC}" >&2
        echo "  The cross-compiled binary may not run on the target." >&2
        echo "  Options:" >&2
        echo "    1. Use a build system with GLIBC <= ${MIN_GLIBC}" >&2
        echo "    2. Compile on the target natively" >&2
        echo "    3. Use a chroot/container matching the target OS" >&2
        echo "    Use --force to override this check." >&2
        echo ""
        if [ "${FORCE}" != "yes" ]
        then
            exit 1
        fi
    else
        echo "CrossCompile: GLIBC check OK (build ${BUILD_GLIBC} <= target min ${MIN_GLIBC})"
    fi
fi

if [ "${WITH_READLINE}" = "no" ]
then
    CONFIGURE_ARGS+=(--without-readline)
    echo "CrossCompile: readline disabled (use --readline to enable)"
fi

echo "CrossCompile: configuring"
(
    cd "${BUILD_DIR}"
    ../configure "${CONFIGURE_ARGS[@]}"
)

# ------------------------------------------------------------------ #
# Build                                                                #
# ------------------------------------------------------------------ #

echo "CrossCompile: building"
make -C "${BUILD_DIR}"

# ------------------------------------------------------------------ #
# Report                                                               #
# ------------------------------------------------------------------ #

echo ""
echo "CrossCompile: build complete"
echo ""
echo "Binaries (libtool .libs/ — actual ELF, not wrapper scripts):"
for BIN in svah svahsim
do
    REAL="${BUILD_DIR}/.libs/${BIN}"
    if [ -f "${REAL}" ]
    then
        printf "  %-10s  %s\n" "${REAL}" \
            "$(file "${REAL}" | sed 's/.*: //')"
    else
        printf "  %-10s  not found in .libs/\n" "${BIN}"
    fi
done

echo ""
echo "Transfer to target (using make install + rsync — recommended):"
echo "  make -C ${BUILD_DIR} install DESTDIR=/tmp/svah-staging"
echo "  rsync -av /tmp/svah-staging/usr/local/ pi@raspberrypi:/usr/local/"
echo "  ssh pi@raspberrypi 'sudo ldconfig'"
echo ""
echo "Or copy individual ELF files directly:"
echo "  scp ${BUILD_DIR}/.libs/svah \\"
echo "      ${BUILD_DIR}/.libs/svahsim \\"
echo "      ${BUILD_DIR}/.libs/libsvah.so.0.0.0 \\"
echo "      pi@raspberrypi:~/"
echo "  ssh pi@raspberrypi 'sudo ldconfig'"
echo ""
echo "Verify on target:"
echo "  ssh pi@raspberrypi 'svah --version'   # if installed via make install"
echo "  ssh pi@raspberrypi './svah --version'  # if copied to home directory"
