git: 4c297a965923 - main - emulators/amiberry: update to 8.3.0

From: Robert Clausecker <fuz_at_FreeBSD.org>
Date: Fri, 16 Oct 2026 19:04:46 UTC
The branch main has been updated by fuz:

URL: https://cgit.FreeBSD.org/ports/commit/?id=4c297a965923d5c1bfb99c5149f706a79fe1ea60

commit 4c297a965923d5c1bfb99c5149f706a79fe1ea60
Author:     polyduekes <polyduekes@proton.me>
AuthorDate: 2026-09-17 08:37:22 +0000
Commit:     Robert Clausecker <fuz@FreeBSD.org>
CommitDate: 2026-10-16 19:02:39 +0000

    emulators/amiberry: update to 8.3.0
    
    Fixed armv7 build failures
    Fixed linking issues
    Fixed WITH_OPTIMISE option
    added support for QEMU UAE PPC Plugin
    
    Changelog: https://github.com/BlitterStudio/amiberry/releases/tag/v8.3.0
    
    Signed-off-by:  polyduekes <polyduekes@proton.me>
    PR:             298601
---
 emulators/amiberry/Makefile                        |  59 ++-
 emulators/amiberry/distinfo                        |  10 +-
 emulators/amiberry/files/build-qemu-uae-plugin.sh  | 427 ++++++++++++++++++++
 emulators/amiberry/files/patch-CMakeLists.txt      |  45 +--
 .../amiberry/files/patch-cmake_Dependencies.cmake  |  21 +
 .../patch-cmake_StandardProjectSettings.cmake      |  16 -
 .../amiberry/files/patch-cmake_optimize.cmake      |  11 +
 .../patch-external_capsimage_CAPSImg_stdafx.h      |  15 +
 emulators/amiberry/files/patch-src_custom.cpp      |  17 +
 .../amiberry/files/patch-src_osdep_fsdb__host.cpp  |  16 -
 .../files/patch-src_osdep_sigsegv__handler.cpp     | 445 ++++++++++-----------
 .../patch-src_pcem_vid__voodoo__codegen__x86.h     |  86 ----
 emulators/amiberry/pkg-plist                       |   3 +-
 13 files changed, 785 insertions(+), 386 deletions(-)

diff --git a/emulators/amiberry/Makefile b/emulators/amiberry/Makefile
index 1358b6510c9c..92f53a888adc 100644
--- a/emulators/amiberry/Makefile
+++ b/emulators/amiberry/Makefile
@@ -1,6 +1,6 @@
 PORTNAME=	amiberry
 DISTVERSIONPREFIX=	v
-DISTVERSION=	8.1.5
+DISTVERSION=	8.3.0
 CATEGORIES=	emulators
 
 MAINTAINER=	polyduekes@proton.me
@@ -10,8 +10,12 @@ WWW=		https://amiberry.com/ \
 
 LICENSE=	GPLv3
 LICENSE_FILE=	${WRKSRC}/LICENSE
+LICENSE_DISTFILES_GPLv2=	qemu-11.0.1.tar.xz
 
 ONLY_FOR_ARCHS=	aarch64 amd64 armv6 armv7 i386 riscv64
+ONLY_FOR_ARCHS_REASON=	only x86(i386), x86_64(AMD64), Aarch64(ARM64), armv6, \
+	armv7, riscv64 and LoongArch64 are supported, see \
+	https://github.com/BlitterStudio/amiberry/wiki/Compile-from-source#supported-architectures
 
 BUILD_DEPENDS=	${LOCALBASE}/include/sys/sysinfo.h:devel/libsysinfo \
 		${LOCALBASE}/share/cmake/nlohmann_json/nlohmann_jsonConfig.cmake:devel/nlohmann-json
@@ -26,13 +30,15 @@ USE_GITHUB=	yes
 GH_ACCOUNT=	BlitterStudio
 USE_SDL=	sdl3 image3
 
-LDFLAGS+=	-lutil
-
 OPTIONS_DEFINE=	BUNDLE_SDL DBUS DOCS GLES IPC_SOCKET LIBENET \
-		LIBMPEG2 LIBSERIALPORT OPENGL PCEM PORTMIDI UAENET_PCAP \
-		VULKAN ZSTD WITH_LTO WITH_OPTIMIZE
+		LIBMPEG2 LIBSERIALPORT OPENGL PCEM PPC PORTMIDI UAENET_PCAP \
+		VULKAN ZSTD WITH_LTO WITH_OPTIMIZE QEMU_PPC
 OPTIONS_DEFAULT=	IPC_SOCKET LIBENET LIBMPEG2 LIBSERIALPORT OPENGL \
-			PCEM PORTMIDI UAENET_PCAP ZSTD
+			PCEM PPC PORTMIDI UAENET_PCAP ZSTD QEMU_PPC
+# QEMU requires a 64-bit architecture
+OPTIONS_EXCLUDE_armv6= QEMU_PPC
+OPTIONS_EXCLUDE_armv7= QEMU_PPC
+OPTIONS_EXCLUDE_i386= QEMU_PPC
 OPTIONS_EXCLUDE_risv64=	PCEM
 OPTIONS_SUB=	yes
 
@@ -45,15 +51,19 @@ LIBMPEG2_DESC=		CD32 FMV support via libmpeg2
 LIBSERIALPORT_DESC=	Serial port emulation via libserialport
 OPENGL_DESC=		OpenGL renderer
 PCEM_DESC=		PCem hardware emulation
+PPC_DESC=		Enable PowerPC accelerator board support
 PORTMIDI_DESC=		MIDI emulation via PortMidi
 UAENET_PCAP_DESC=	uaenet backend via libpcap
 VULKAN_DESC=		Experimental Vulkan renderer
 ZSTD_DESC=		CHD compressed disk image support via Zstandard
 WITH_LTO_DESC=		Link Time Optimization
 WITH_OPTIMIZE_DESC=	Native CPU Optimization
+QEMU_PPC_DESC=		Enable QEMU-UAE PowerPC plugin support
 
 VULKAN_PREVENTS=	OPENGL
 
+QEMU_PPC_IMPLIES=	PPC
+
 BUNDLE_SDL_CMAKE_BOOL=	BUNDLE_SDL
 DBUS_CMAKE_BOOL=	USE_DBUS
 GLES_CMAKE_BOOL=	USE_GLES
@@ -63,12 +73,14 @@ LIBMPEG2_CMAKE_BOOL=	USE_LIBMPEG2
 LIBSERIALPORT_CMAKE_BOOL=	USE_LIBSERIALPORT
 OPENGL_CMAKE_BOOL=	USE_OPENGL
 PCEM_CMAKE_BOOL=	USE_PCEM
+PPC_CMAKE_BOOL=		USE_PPC
 PORTMIDI_CMAKE_BOOL=	USE_PORTMIDI
 UAENET_PCAP_CMAKE_BOOL=	USE_UAENET_PCAP
 VULKAN_CMAKE_BOOL=	USE_VULKAN
 ZSTD_CMAKE_BOOL=	USE_ZSTD
 WITH_LTO_CMAKE_BOOL=	WITH_LTO
 WITH_OPTIMIZE_CMAKE_BOOL=	WITH_OPTIMIZE
+QEMU_PPC_CMAKE_BOOL=	USE_QEMU_PPC
 
 DBUS_LIB_DEPENDS=	libdbus-1.so:devel/dbus
 GLES_LIB_DEPENDS=	libEGL.so:graphics/libglvnd \
@@ -80,6 +92,41 @@ OPENGL_LIB_DEPENDS=	libOpenGL.so:graphics/libglvnd
 PORTMIDI_LIB_DEPENDS=	libportmidi.so:audio/portmidi
 UAENET_PCAP_LIB_DEPENDS=	libpcap.so:net/libpcap
 VULKAN_LIB_DEPENDS=	libvulkan.so:graphics/vulkan-loader
+QEMU_PPC_BUILD_DEPENDS=	${PYTHON_PKGNAMEPREFIX}pip>0:devel/py-pip@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}setuptools>0:devel/py-setuptools@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}wheel>0:devel/py-wheel@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}qemu.qmp>0:emulators/py-qemu.qmp@${PY_FLAVOR}
+QEMU_PPC_LIB_DEPENDS=	libdw.so:devel/elfutils \
+			libfdt.so:sysutils/dtc
+QEMU_PPC_USES=		inotify
 ZSTD_LIB_DEPENDS=	libzstd.so:archivers/zstd
 
+QEMU_PPC_MASTER_SITES=	https://download.qemu.org/:qemu
+QEMU_PPC_DISTFILES=	qemu-11.0.1.tar.xz:qemu
+
+QEMU_PPC_GH_TUPLE=	BlitterStudio:amiberry-qemu-uae:a12bb101f0d23310431726ca4ff643828e68f7b5:qemu_plugin
+
+QEMU_PPC_USES=	gnome python:build
+QEMU_PPC_USE=	gnome=glib20
+
+QEMU_PPC_CMAKE_ON=	-DQEMU_UAE_PLUGIN=${WRKSRC}/qemu-uae.so
+
+pre-build-QEMU_PPC-on:
+	@${ECHO_MSG} "Building QEMU-UAE Plugin..."
+	(cd ${WRKSRC_qemu_plugin} && ${SETENV} ${MAKE_ENV} \
+	QEMU_UAE_NINJA=ninja \
+	QEMU_UAE_STRIP_TOOL=strip \
+	${SH} ./build-qemu-uae-plugin.sh \
+	--tarball ${DISTDIR}/qemu-11.0.1.tar.xz \
+	--source-dir ${WRKDIR}/qemu-11.0.1 \
+	--output ${WRKSRC}/qemu-uae.so \
+	-j ${MAKE_JOBS_NUMBER} \
+	-- \
+	--enable-fdt=system \
+	--extra-cflags="-I${LOCALBASE}/include" \
+	--extra-ldflags="-L${LOCALBASE}/lib")
+
+post-extract-QEMU_PPC-on:
+	@${CP} ${FILESDIR}/build-qemu-uae-plugin.sh ${WRKSRC_qemu_plugin}/
+
 .include <bsd.port.mk>
diff --git a/emulators/amiberry/distinfo b/emulators/amiberry/distinfo
index 2b6a6c013877..f27b698dd1e9 100644
--- a/emulators/amiberry/distinfo
+++ b/emulators/amiberry/distinfo
@@ -1,3 +1,7 @@
-TIMESTAMP = 1776707171
-SHA256 (BlitterStudio-amiberry-v8.1.5_GH0.tar.gz) = 33ef1343fef5ebd4bad5a08efc995e38fd918aa2c3a472867ab41b68c53dac82
-SIZE (BlitterStudio-amiberry-v8.1.5_GH0.tar.gz) = 17208280
+TIMESTAMP = 1791274086
+SHA256 (qemu-11.0.1.tar.xz) = 0d235f5820278d914a3155ec27af8e4258d697ea892895570807d69c0cb8cd64
+SIZE (qemu-11.0.1.tar.xz) = 141368572
+SHA256 (BlitterStudio-amiberry-v8.3.0_GH0.tar.gz) = 881628c2465fe28063b8444350e78167e7a9ed047def66b9ef3cfdabd4bdc1d6
+SIZE (BlitterStudio-amiberry-v8.3.0_GH0.tar.gz) = 18185745
+SHA256 (BlitterStudio-amiberry-qemu-uae-a12bb101f0d23310431726ca4ff643828e68f7b5_GH0.tar.gz) = 91795f83516eb8ee857b1fbd3ff9cace70118baf5b26ecfc47d775dfe6ef084d
+SIZE (BlitterStudio-amiberry-qemu-uae-a12bb101f0d23310431726ca4ff643828e68f7b5_GH0.tar.gz) = 41436
diff --git a/emulators/amiberry/files/build-qemu-uae-plugin.sh b/emulators/amiberry/files/build-qemu-uae-plugin.sh
new file mode 100755
index 000000000000..90ec4ca240c2
--- /dev/null
+++ b/emulators/amiberry/files/build-qemu-uae-plugin.sh
@@ -0,0 +1,427 @@
+#!/bin/sh
+set -eu
+
+qemu_version="11.0.1"
+qemu_archive="qemu-${qemu_version}.tar.xz"
+qemu_url_default="https://download.qemu.org/${qemu_archive}"
+qemu_sha256="0d235f5820278d914a3155ec27af8e4258d697ea892895570807d69c0cb8cd64"
+
+script_dir="$(cd "$(dirname "$0")" && pwd)"
+patch_dir="${QEMU_UAE_PATCH_DIR:-${script_dir}/patches}"
+patch_file="${QEMU_UAE_PATCH:-}"
+work_dir="${QEMU_UAE_WORK_DIR:-${script_dir}/build}"
+qemu_url="${QEMU_UAE_QEMU_URL:-${qemu_url_default}}"
+tarball="${QEMU_UAE_TARBALL:-}"
+source_dir="${QEMU_UAE_SOURCE_DIR:-}"
+output_plugin="${QEMU_UAE_OUTPUT_PLUGIN:-}"
+deps_prefix="${QEMU_UAE_DEPS_PREFIX:-}"
+jobs="${QEMU_UAE_JOBS:-}"
+clean=0
+verify=1
+strip_plugin="${QEMU_UAE_STRIP:-1}"
+static_deps="${QEMU_UAE_STATIC_DEPS:-0}"
+host_system="$(uname -s)"
+
+case "${host_system}" in
+    Darwin*)
+        plugin_extension="dylib"
+        ;;
+    MINGW*|MSYS*|CYGWIN*)
+        plugin_extension="dll"
+        ;;
+    *)
+        plugin_extension="so"
+        ;;
+esac
+plugin_name="qemu-uae.${plugin_extension}"
+
+usage() {
+    cat <<EOF
+Usage: $0 [options] [-- configure-arg ...]
+
+Download QEMU ${qemu_version}, apply the QEMU-UAE patch deck, and build
+the native qemu-uae plugin artifact.
+
+Options:
+  --work-dir DIR       Working directory. Default: ./build next to script.
+  --source-dir DIR     Patched QEMU source directory.
+  --tarball FILE       Use an existing QEMU ${qemu_version} tarball.
+  --url URL            Download URL. Default: ${qemu_url_default}
+  --output FILE        Copy the finished qemu-uae plugin to FILE.
+  --patch-dir DIR      Directory containing ordered *.patch files.
+  -j, --jobs N         Ninja parallelism.
+  --clean              Remove the source directory before extracting.
+  --no-verify          Skip tarball SHA-256 verification.
+  --no-strip           Keep debug/local symbols in the output plugin.
+  --static-deps        Link external dependencies statically. Windows only.
+  -h, --help           Show this help.
+
+Environment:
+  QEMU_UAE_PATCH       Single patch file override.
+  QEMU_UAE_PATCH_DIR   Directory containing ordered *.patch files.
+  QEMU_UAE_DEPS_PREFIX  Prefix containing dependency pkg-config files.
+  QEMU_UAE_NINJA        Ninja executable. Defaults to ninja in PATH.
+  QEMU_UAE_STATIC_DEPS  Set to 1/true/yes/on to enable --static-deps.
+  QEMU_UAE_STRIP        Set to 0/false/no/off to keep symbols.
+  QEMU_UAE_STRIP_TOOL   Strip executable. Defaults to llvm-strip or strip.
+  MACOSX_DEPLOYMENT_TARGET
+                         macOS deployment target. Default on Darwin: 13.0.
+EOF
+}
+
+die() {
+    echo "error: $*" >&2
+    exit 1
+}
+
+while [ $# -gt 0 ]; do
+    case "$1" in
+        --work-dir)
+            [ $# -ge 2 ] || die "--work-dir requires an argument"
+            work_dir="$2"
+            shift 2
+            ;;
+        --source-dir)
+            [ $# -ge 2 ] || die "--source-dir requires an argument"
+            source_dir="$2"
+            shift 2
+            ;;
+        --tarball)
+            [ $# -ge 2 ] || die "--tarball requires an argument"
+            tarball="$2"
+            shift 2
+            ;;
+        --url)
+            [ $# -ge 2 ] || die "--url requires an argument"
+            qemu_url="$2"
+            shift 2
+            ;;
+        --output)
+            [ $# -ge 2 ] || die "--output requires an argument"
+            output_plugin="$2"
+            shift 2
+            ;;
+        --patch-dir)
+            [ $# -ge 2 ] || die "--patch-dir requires an argument"
+            patch_dir="$2"
+            shift 2
+            ;;
+        -j|--jobs)
+            [ $# -ge 2 ] || die "$1 requires an argument"
+            jobs="$2"
+            shift 2
+            ;;
+        --clean)
+            clean=1
+            shift
+            ;;
+        --no-verify)
+            verify=0
+            shift
+            ;;
+        --no-strip)
+            strip_plugin=0
+            shift
+            ;;
+        --static-deps)
+            static_deps=1
+            shift
+            ;;
+        -h|--help)
+            usage
+            exit 0
+            ;;
+        --)
+            shift
+            break
+            ;;
+        *)
+            die "unknown option: $1"
+            ;;
+    esac
+done
+
+case "${strip_plugin}" in
+    0|false|False|FALSE|no|No|NO|off|Off|OFF)
+        strip_plugin=0
+        ;;
+    *)
+        strip_plugin=1
+        ;;
+esac
+
+case "${static_deps}" in
+    1|true|True|TRUE|yes|Yes|YES|on|On|ON)
+        static_deps=1
+        ;;
+    0|false|False|FALSE|no|No|NO|off|Off|OFF)
+        static_deps=0
+        ;;
+    *)
+        die "invalid QEMU_UAE_STATIC_DEPS value: ${static_deps}"
+        ;;
+esac
+
+if [ "${static_deps}" = "1" ]; then
+    case "${host_system}" in
+        MINGW*|MSYS*|CYGWIN*)
+            ;;
+        *)
+            die "--static-deps is currently supported only on Windows/MSYS2 hosts"
+            ;;
+    esac
+fi
+
+download_dir="${work_dir}/downloads"
+if [ -z "${tarball}" ]; then
+    tarball="${download_dir}/${qemu_archive}"
+fi
+if [ -z "${source_dir}" ]; then
+    source_dir="${work_dir}/qemu-${qemu_version}-uae"
+fi
+if [ -z "${output_plugin}" ]; then
+    output_plugin="${work_dir}/${plugin_name}"
+fi
+
+if [ -z "${jobs}" ]; then
+    if command -v sysctl >/dev/null 2>&1; then
+        jobs="$(sysctl -n hw.ncpu 2>/dev/null || true)"
+    fi
+    if [ -z "${jobs}" ] && command -v nproc >/dev/null 2>&1; then
+        jobs="$(nproc)"
+    fi
+    jobs="${jobs:-4}"
+fi
+
+if [ -n "${deps_prefix}" ]; then
+    [ -d "${deps_prefix}" ] || die "dependency prefix does not exist: ${deps_prefix}"
+    deps_prefix="$(cd "${deps_prefix}" && pwd)"
+    export PATH="${deps_prefix}/bin:${PATH}"
+    export PKG_CONFIG_LIBDIR="${deps_prefix}/lib/pkgconfig:${deps_prefix}/share/pkgconfig${PKG_CONFIG_LIBDIR:+:${PKG_CONFIG_LIBDIR}}"
+fi
+
+if [ "${host_system}" = "Darwin" ]; then
+    export MACOSX_DEPLOYMENT_TARGET="${MACOSX_DEPLOYMENT_TARGET:-13.0}"
+fi
+
+download_qemu() {
+    if [ -f "${tarball}" ]; then
+        return
+    fi
+
+    mkdir -p "$(dirname "${tarball}")"
+    local tmp="${tarball}.tmp"
+    rm -f "${tmp}"
+
+    if command -v curl >/dev/null 2>&1; then
+        curl -L --fail -o "${tmp}" "${qemu_url}"
+    elif command -v wget >/dev/null 2>&1; then
+        wget -O "${tmp}" "${qemu_url}"
+    else
+        die "curl or wget is required to download ${qemu_url}"
+    fi
+
+    mv "${tmp}" "${tarball}"
+}
+
+sha256_file() {
+    if command -v sha256sum >/dev/null 2>&1; then
+        sha256sum "$1" | awk '{print $1}'
+    elif command -v shasum >/dev/null 2>&1; then
+        shasum -a 256 "$1" | awk '{print $1}'
+    else
+        return 1
+    fi
+}
+
+verify_qemu() {
+    [ "${verify}" = "1" ] || return
+
+    local actual
+    actual="$(sha256_file "${tarball}")" || die "no SHA-256 tool found; use --no-verify to skip"
+    [ "${actual}" = "${qemu_sha256}" ] || die "SHA-256 mismatch for ${tarball}"
+}
+
+extract_qemu() {
+    if [ "${clean}" = "1" ]; then
+        rm -rf "${source_dir}"
+    fi
+    if [ -d "${source_dir}" ]; then
+        return
+    fi
+
+    mkdir -p "${work_dir}" "$(dirname "${source_dir}")"
+    local extract_dir="${work_dir}/.extract.$$"
+    rm -rf "${extract_dir}"
+    mkdir -p "${extract_dir}"
+
+    case "${host_system}" in
+        MINGW*|MSYS*|CYGWIN*)
+            tar -xf "${tarball}" -C "${extract_dir}" \
+                --exclude="qemu-${qemu_version}/roms" \
+                --exclude="qemu-${qemu_version}/roms/*" \
+                --exclude="qemu-${qemu_version}/tests/lcitool" \
+                --exclude="qemu-${qemu_version}/tests/lcitool/*"
+            ;;
+        *)
+            tar -xf "${tarball}" -C "${extract_dir}"
+            ;;
+    esac
+
+    mv "${extract_dir}/qemu-${qemu_version}" "${source_dir}"
+    rm -rf "${extract_dir}"
+}
+
+apply_qemu_patch_file() {
+    local patch_file="$1"
+    local patch_name
+    patch_name="$(basename "${patch_file}")"
+    local forward_output
+    local reverse_output
+    forward_output="$(mktemp)"
+    reverse_output="$(mktemp)"
+
+    # Using -C instead of --dry-run for FreeBSD patch compatibility
+    if (cd "${source_dir}" && patch -p1 -C -f < "${patch_file}" >"${forward_output}" 2>&1); then
+        rm -f "${forward_output}" "${reverse_output}"
+        echo "applying ${patch_name}"
+        (cd "${source_dir}" && patch -p1 -f < "${patch_file}")
+    elif (cd "${source_dir}" && patch -p1 -R -C -f < "${patch_file}" >"${reverse_output}" 2>&1); then
+        rm -f "${forward_output}" "${reverse_output}"
+        echo "${patch_name} already applied"
+    else
+        echo "${patch_name} forward check failed:" >&2
+        cat "${forward_output}" >&2
+        echo "${patch_name} reverse check failed:" >&2
+        cat "${reverse_output}" >&2
+        rm -f "${forward_output}" "${reverse_output}"
+        die "${patch_name} does not apply cleanly to ${source_dir}"
+    fi
+}
+
+apply_qemu_patches() {
+    if [ -n "${patch_file}" ]; then
+        [ -f "${patch_file}" ] || die "patch not found: ${patch_file}"
+        apply_qemu_patch_file "${patch_file}"
+    else
+        [ -d "${patch_dir}" ] || die "patch directory not found: ${patch_dir}"
+
+        # POSIX safe iteration of sorted files
+        for patch in $(ls "${patch_dir}"/*.patch 2>/dev/null | sort); do
+            [ -f "${patch}" ] || continue
+            apply_qemu_patch_file "${patch}"
+        done
+    fi
+
+    chmod +x "${source_dir}/configure-qemu-uae"
+}
+
+find_ninja() {
+    if [ -n "${QEMU_UAE_NINJA:-}" ]; then
+        echo "${QEMU_UAE_NINJA}"
+    elif command -v ninja >/dev/null 2>&1; then
+        command -v ninja
+    elif command -v ninja-build >/dev/null 2>&1; then
+        command -v ninja-build
+    else
+        return 1
+    fi
+}
+
+find_strip() {
+    if [ -n "${QEMU_UAE_STRIP_TOOL:-}" ]; then
+        command -v "${QEMU_UAE_STRIP_TOOL}" || return 1
+    elif command -v llvm-strip >/dev/null 2>&1; then
+        command -v llvm-strip
+    elif command -v strip >/dev/null 2>&1; then
+        command -v strip
+    else
+        return 1
+    fi
+}
+
+file_size_bytes() {
+    stat -c '%s' "$1" 2>/dev/null || stat -f '%z' "$1" 2>/dev/null || wc -c < "$1" | awk '{print $1}'
+}
+
+strip_qemu_uae_plugin() {
+    local plugin="$1"
+    [ "${strip_plugin}" = "1" ] || return
+
+    local strip_tool
+    if ! strip_tool="$(find_strip)"; then
+        echo "warning: no strip tool found; leaving ${plugin_name} unstripped" >&2
+        return
+    fi
+
+    local before
+    local after
+    before="$(file_size_bytes "${plugin}")"
+    case "${host_system}" in
+        Darwin*)
+            "${strip_tool}" -S -x "${plugin}"
+            ;;
+        *)
+            "${strip_tool}" --strip-unneeded "${plugin}"
+            ;;
+    esac
+    after="$(file_size_bytes "${plugin}")"
+    echo "stripped ${plugin_name}: ${before} -> ${after} bytes"
+}
+
+build_qemu_uae() {
+    local ninja
+    ninja="$(find_ninja)" || die "ninja not found; set QEMU_UAE_NINJA"
+
+    if [ "${static_deps}" = "1" ]; then
+        local pkg_config_tool="${PKG_CONFIG:-}"
+        if [ -z "${pkg_config_tool}" ]; then
+            pkg_config_tool="$(command -v pkg-config || command -v pkgconf || true)"
+            [ -n "${pkg_config_tool}" ] || die "pkg-config not found"
+        fi
+        if command -v cygpath >/dev/null 2>&1; then
+            local pkg_config_exe="${pkg_config_tool%% *}"
+            local pkg_config_args=""
+            if [ "${pkg_config_tool}" != "${pkg_config_exe}" ]; then
+                pkg_config_args="${pkg_config_tool#${pkg_config_exe}}"
+            fi
+            pkg_config_exe="$(cygpath -m "${pkg_config_exe}")"
+            pkg_config_tool="${pkg_config_exe}${pkg_config_args}"
+        fi
+        case " ${pkg_config_tool} " in
+            *" --static "*)
+                export PKG_CONFIG="${pkg_config_tool}"
+                ;;
+            *)
+                export PKG_CONFIG="${pkg_config_tool} --static"
+                ;;
+        esac
+        # Inject standard static flags alongside whatever user args are in $@
+        set -- ./configure-qemu-uae --ninja="${ninja}" --static --extra-ldflags=-static "$@"
+    else
+        # Prepend configure script and ninja explicitly to user args
+        set -- ./configure-qemu-uae --ninja="${ninja}" "$@"
+    fi
+
+    (
+        cd "${source_dir}" || exit 1
+        "$@"
+    )
+    "${ninja}" -C "${source_dir}/build" -j "${jobs}" "${plugin_name}"
+
+    local built_plugin="${source_dir}/build/${plugin_name}"
+    [ -f "${built_plugin}" ] || die "${plugin_name} was not produced"
+    mkdir -p "$(dirname "${output_plugin}")"
+    cp "${built_plugin}" "${output_plugin}"
+    strip_qemu_uae_plugin "${output_plugin}"
+}
+
+download_qemu
+verify_qemu
+extract_qemu
+apply_qemu_patches
+
+# $@ at this point contains only the leftover configure arguments
+build_qemu_uae "$@"
+
+echo "${output_plugin}"
diff --git a/emulators/amiberry/files/patch-CMakeLists.txt b/emulators/amiberry/files/patch-CMakeLists.txt
index 46b812f61442..818f5c11368d 100644
--- a/emulators/amiberry/files/patch-CMakeLists.txt
+++ b/emulators/amiberry/files/patch-CMakeLists.txt
@@ -1,37 +1,12 @@
---- CMakeLists.txt.orig	2026-04-22 13:26:02 UTC
+--- CMakeLists.txt.orig	2026-10-04 18:34:33 UTC
 +++ CMakeLists.txt
-@@ -142,7 +142,7 @@ include(cmake/Dependencies.cmake)
- 
- # Install rules may need dependency targets, such as SDL3 and SDL3_image,
- # so include them after dependency discovery.
--if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
-+if (CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
-     include(cmake/linux/install.cmake)
- elseif (IOS)
-     include(cmake/ios/install.cmake)
-@@ -153,25 +153,3 @@ include(packaging/CMakeLists.txt)
- endif ()
- 
- include(packaging/CMakeLists.txt)
--
--# Link libraries (FreeBSD needs correct order)
--if(TARGET amiberry AND CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
--    target_link_options(amiberry PRIVATE -L/usr/local/lib)
--    # Apply FreeBSD pkg-config include/link dirs
--    if(FREEBSD_INCLUDE_DIRS)
--        target_include_directories(amiberry PRIVATE ${FREEBSD_INCLUDE_DIRS})
+@@ -139,9 +139,6 @@ if(QEMU_UAE_PLUGIN)
+         message(FATAL_ERROR "QEMU_UAE_PLUGIN requires USE_PPC=ON and USE_QEMU_PPC=ON")
+     endif()
+     get_filename_component(QEMU_UAE_PLUGIN "${QEMU_UAE_PLUGIN}" ABSOLUTE BASE_DIR "${CMAKE_SOURCE_DIR}")
+-    if(NOT EXISTS "${QEMU_UAE_PLUGIN}")
+-        message(FATAL_ERROR "QEMU_UAE_PLUGIN does not exist: ${QEMU_UAE_PLUGIN}")
 -    endif()
--    if(FREEBSD_LIBRARIES)
--        target_link_libraries(amiberry PRIVATE ${FREEBSD_LIBRARIES})
--    endif()
--
--    # forkpty() lives in libutil on FreeBSD
--    target_link_libraries(amiberry PRIVATE util)
--
--    # libiconv_* symbols come from ports/converters/libiconv
--    find_library(LIBICONV_LIBRARY NAMES iconv PATHS /usr/local/lib REQUIRED)
--    target_link_libraries(amiberry PRIVATE ${LIBICONV_LIBRARY})
--
--    # existing libs
--    target_link_libraries(amiberry PRIVATE ${LIBUSB_LIBRARY} serialport ${EXTRA_LIBS})
--endif()
+     set(QEMU_UAE_PLUGIN "${QEMU_UAE_PLUGIN}" CACHE FILEPATH "Path to a prebuilt qemu-uae plugin artifact to bundle" FORCE)
+     if(QEMU_UAE_PLUGIN_DIR)
+         get_filename_component(QEMU_UAE_PLUGIN_DIR "${QEMU_UAE_PLUGIN_DIR}" ABSOLUTE BASE_DIR "${CMAKE_SOURCE_DIR}")
diff --git a/emulators/amiberry/files/patch-cmake_Dependencies.cmake b/emulators/amiberry/files/patch-cmake_Dependencies.cmake
new file mode 100644
index 000000000000..3a7222f266cf
--- /dev/null
+++ b/emulators/amiberry/files/patch-cmake_Dependencies.cmake
@@ -0,0 +1,21 @@
+--- cmake/Dependencies.cmake.orig	2026-06-19 16:11:53 UTC
++++ cmake/Dependencies.cmake
+@@ -19,7 +19,7 @@ if (USE_DBUS)
+     find_package(PkgConfig REQUIRED)
+     pkg_check_modules(DBUS REQUIRED dbus-1)
+     target_include_directories(${PROJECT_NAME} PRIVATE ${DBUS_INCLUDE_DIRS})
+-    target_link_libraries(${PROJECT_NAME} PRIVATE ${DBUS_LIBRARIES})
++    target_link_libraries(${PROJECT_NAME} PRIVATE ${DBUS_LINK_LIBRARIES})
+ endif ()
+ 
+ if (USE_IPC_SOCKET)
+@@ -771,7 +771,8 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
+ elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
+     find_library(UTIL_LIBRARY util REQUIRED)
+     # REQUIRED will make sure the build fails earlier if libutil isn't found
+-    target_link_libraries(${PROJECT_NAME} PRIVATE ${UTIL_LIBRARY} iconv)
++    find_library(ICONV_LIB iconv PATHS /usr/local/lib REQUIRED)
++    target_link_libraries(${PROJECT_NAME} PRIVATE ${UTIL_LIBRARY} ${ICONV_LIB})
+ elseif(CMAKE_SYSTEM_NAME STREQUAL "Haiku")
+     target_link_libraries(${PROJECT_NAME} PRIVATE network iconv bsd)
+ endif()
diff --git a/emulators/amiberry/files/patch-cmake_StandardProjectSettings.cmake b/emulators/amiberry/files/patch-cmake_StandardProjectSettings.cmake
deleted file mode 100644
index 11ec8660d03f..000000000000
--- a/emulators/amiberry/files/patch-cmake_StandardProjectSettings.cmake
+++ /dev/null
@@ -1,16 +0,0 @@
---- cmake/StandardProjectSettings.cmake.orig	2026-04-26 10:53:54 UTC
-+++ cmake/StandardProjectSettings.cmake
-@@ -83,6 +83,13 @@ if(WITH_LTO)
- endif()
- 
- if(WITH_LTO)
-+	# ensure LTO links with lld on FreeBSD/clang.
-+    if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")
-+        string(APPEND CMAKE_EXE_LINKER_FLAGS " -fuse-ld=lld")
-+        string(APPEND CMAKE_SHARED_LINKER_FLAGS " -fuse-ld=lld")
-+        string(APPEND CMAKE_MODULE_LINKER_FLAGS " -fuse-ld=lld")
-+    endif()
-+
-     include(CheckIPOSupported)
-     check_ipo_supported(RESULT lto_supported OUTPUT lto_error)
-     if(lto_supported)
diff --git a/emulators/amiberry/files/patch-cmake_optimize.cmake b/emulators/amiberry/files/patch-cmake_optimize.cmake
new file mode 100644
index 000000000000..5401ad0f55be
--- /dev/null
+++ b/emulators/amiberry/files/patch-cmake_optimize.cmake
@@ -0,0 +1,11 @@
+--- cmake/optimize.cmake.orig	2026-10-04 18:52:13 UTC
++++ cmake/optimize.cmake
+@@ -12,7 +12,7 @@ if(CMAKE_C_COMPILER_ID MATCHES "Clang")
+     )
+ 
+     if(CLANG_TARGET_CPU)
+-        set(OPTIMIZED_FLAGS "-mcpu=${CLANG_TARGET_CPU}")
++        set(OPTIMIZED_FLAGS "-mtune=${CLANG_TARGET_CPU}")
+         message(STATUS "Applied Clang optimization flags: ${OPTIMIZED_FLAGS}")
+     else()
+         message(WARNING "Could not extract Clang optimization flags")
diff --git a/emulators/amiberry/files/patch-external_capsimage_CAPSImg_stdafx.h b/emulators/amiberry/files/patch-external_capsimage_CAPSImg_stdafx.h
new file mode 100644
index 000000000000..93a951c7a023
--- /dev/null
+++ b/emulators/amiberry/files/patch-external_capsimage_CAPSImg_stdafx.h
@@ -0,0 +1,15 @@
+--- external/capsimage/CAPSImg/stdafx.h.orig	2026-08-18 12:06:20 UTC
++++ external/capsimage/CAPSImg/stdafx.h
+@@ -60,6 +60,12 @@
+ #endif
+ #endif
+ 
++#ifdef __FreeBSD__
++#define ftello64 ftello
++#define fseeko64 fseeko
++#define fopen64 fopen
++#endif
++
+ #ifndef _WIN32
+ 
+ #define __cdecl
diff --git a/emulators/amiberry/files/patch-src_custom.cpp b/emulators/amiberry/files/patch-src_custom.cpp
new file mode 100644
index 000000000000..a024b38656d4
--- /dev/null
+++ b/emulators/amiberry/files/patch-src_custom.cpp
@@ -0,0 +1,17 @@
+--- src/custom.cpp.orig	2026-09-17 07:30:24 UTC
++++ src/custom.cpp
+@@ -7689,10 +7689,10 @@ static int REGPARAM2 custom_wput_1(uaecptr addr, uae_u
+ 		} else {
+ 			int reg = addr & 0x1fe;
+ 			if (aga_mode) {
+-				custom_wput_dma64(reg, static_cast<uaecptr>(NULL), v, c);
+-			} else {
+-				write_drga(reg, static_cast<uaecptr>(NULL), v);
+-			}
++				custom_wput_dma64(reg, 0, v, c);
++            } else {
++				write_drga(reg, 0, v);
++            }
+ 		}
+ 	}
+ 	return ret;
diff --git a/emulators/amiberry/files/patch-src_osdep_fsdb__host.cpp b/emulators/amiberry/files/patch-src_osdep_fsdb__host.cpp
deleted file mode 100644
index 54696492b465..000000000000
--- a/emulators/amiberry/files/patch-src_osdep_fsdb__host.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
---- src/osdep/fsdb_host.cpp.orig	2026-04-25 15:03:50 UTC
-+++ src/osdep/fsdb_host.cpp
-@@ -642,7 +642,13 @@ bool my_utime(const char* name, const struct mytimeval
- 		ok = _utime(path_utf8.c_str(), &utb) == 0;
- #else
- 		struct timeval times[2];
-+#if defined(__FreeBSD__) && defined(__i386__)
-+		times[0].tv_sec = static_cast<time_t>(mtv.tv_sec);
-+		times[0].tv_usec = static_cast<suseconds_t>(mtv.tv_usec);
-+		times[1] = times[0];
-+#else
- 		times[0] = times[1] = { mtv.tv_sec, mtv.tv_usec };
-+#endif
- 		ok = utimes(path_utf8.c_str(), times) == 0;
- #endif
- 	}
diff --git a/emulators/amiberry/files/patch-src_osdep_sigsegv__handler.cpp b/emulators/amiberry/files/patch-src_osdep_sigsegv__handler.cpp
index 703fc5bfb4ab..8b1fd0af69ca 100644
--- a/emulators/amiberry/files/patch-src_osdep_sigsegv__handler.cpp
+++ b/emulators/amiberry/files/patch-src_osdep_sigsegv__handler.cpp
@@ -1,240 +1,239 @@
---- src/osdep/sigsegv_handler.cpp.orig	2026-04-26 06:59:39 UTC
+--- src/osdep/sigsegv_handler.cpp.orig	2026-06-19 16:11:53 UTC
 +++ src/osdep/sigsegv_handler.cpp
-@@ -63,6 +63,9 @@ void init_max_signals()
- #else
- #include <sys/ucontext.h>
+@@ -2,7 +2,7 @@
+  * sigsegv_linux_arm.cpp - x86_64 Linux SIGSEGV handler
+  *
+  * Copyright (c) 2014 Jens Heitmann ARAnyM dev team (see AUTHORS)
+- * 
++ *
+  * Inspired by Bernie Meyer's UAE-JIT and Gwenole Beauchesne's Basilisk II-JIT
+  *
+  * This file is part of the ARAnyM project which builds a new and powerful
+@@ -564,8 +564,8 @@ extern void raise_in_cl_list(blockinfo* bi);
+ extern void invalidate_block(blockinfo* bi);
+ extern void raise_in_cl_list(blockinfo* bi);
  #endif
-+#if defined(__FreeBSD__) && defined(CPU_AARCH64)
-+#include <machine/ucontext.h>
-+#endif
- #include <csignal>
- #include <dlfcn.h>
+-  
  
-@@ -154,8 +157,10 @@ static int handle_exception(mcontext_t sigcont, long f
- #endif
- {
- 	int handled = HANDLE_EXCEPTION_NONE;
-+#if defined(__FreeBSD__) && defined(CPU_AARCH64)
-+	auto fault_pc = static_cast<uintptr>(sigcont->mc_gpregs.gp_elr);
-+#elif !defined(__MACH__)
- // Mac OS X struct for this is different
--#ifndef __MACH__
- 	auto fault_pc = static_cast<uintptr>(sigcont->pc);
- #else
- 	auto fault_pc = static_cast<uintptr>(sigcont->__ss.__pc);
-@@ -199,7 +204,9 @@ static int handle_exception(mcontext_t sigcont, long f
- 		// Check for stupid RAM detection of kickstart
- 		if (a3000lmem_bank.allocated_size > 0 && amiga_addr >= a3000lmem_bank.start - 0x00100000 && amiga_addr < a3000lmem_bank.start - 0x00100000 + 8) {
- 			output_log(_T("  Stupid kickstart detection for size of ramsey_low at 0x%08x.\n"), amiga_addr);
--#ifndef __MACH__
-+#if defined(__FreeBSD__) && defined(CPU_AARCH64)
-+			sigcont->mc_gpregs.gp_elr += 4;
-+#elif !defined(__MACH__)
- 			sigcont->pc += 4;
- #else
- 			sigcont->__ss.__pc += 4;
-@@ -211,7 +218,9 @@ static int handle_exception(mcontext_t sigcont, long f
- 		// Check for stupid RAM detection of kickstart
- 		if (a3000hmem_bank.allocated_size > 0 && amiga_addr >= a3000hmem_bank.start + a3000hmem_bank.allocated_size && amiga_addr < a3000hmem_bank.start + a3000hmem_bank.allocated_size + 8) {
- 			output_log(_T("  Stupid kickstart detection for size of ramsey_high at 0x%08x.\n"), amiga_addr);
--#ifndef __MACH__
-+#if defined(__FreeBSD__) && defined(CPU_AARCH64)
-+			sigcont->mc_gpregs.gp_elr += 4;
-+#elif !defined(__MACH__)
- 			sigcont->pc += 4;
- #else
- 			sigcont->__ss.__pc += 4;
-@@ -241,43 +250,58 @@ static int handle_exception(mcontext_t sigcont, long f
- 		transfer_type_t transfer_type = TYPE_UNKNOWN;
- 		int transfer_size = SIZE_UNKNOWN;
++
+ #define SHOW_DETAILS 2
  
--			const auto get_reg_w = [&](const int reg) -> uae_u32 {
--				if (reg == 31)
--					return 0;
--#ifndef __MACH__
--				return static_cast<uae_u32>(sigcont->regs[reg]);
-+				const auto get_reg_w = [&](const int reg) -> uae_u32 {
-+					if (reg == 31)
-+						return 0;
-+#if defined(__FreeBSD__) && defined(CPU_AARCH64)
-+					if (reg < 30)
-+						return static_cast<uae_u32>(sigcont->mc_gpregs.gp_x[reg]);
-+					return static_cast<uae_u32>(sigcont->mc_gpregs.gp_lr);
-+#elif !defined(__MACH__)
-+					return static_cast<uae_u32>(sigcont->regs[reg]);
- #else
--				return static_cast<uae_u32>(sigcont->__ss.__x[reg]);
-+					return static_cast<uae_u32>(sigcont->__ss.__x[reg]);
- #endif
--			};
--			const auto get_reg_x = [&](const int reg) -> uae_u64 {
--				if (reg == 31)
--					return 0;
--#ifndef __MACH__
--				return static_cast<uae_u64>(sigcont->regs[reg]);
-+				};
-+				const auto get_reg_x = [&](const int reg) -> uae_u64 {
-+					if (reg == 31)
-+						return 0;
-+#if defined(__FreeBSD__) && defined(CPU_AARCH64)
-+					if (reg < 30)
-+						return static_cast<uae_u64>(sigcont->mc_gpregs.gp_x[reg]);
-+					return static_cast<uae_u64>(sigcont->mc_gpregs.gp_lr);
-+#elif !defined(__MACH__)
-+					return static_cast<uae_u64>(sigcont->regs[reg]);
- #else
--				return static_cast<uae_u64>(sigcont->__ss.__x[reg]);
-+					return static_cast<uae_u64>(sigcont->__ss.__x[reg]);
- #endif
--			};
--			const auto get_base_x = [&](const int reg) -> uae_u64 {
--				if (reg == 31) {
--#ifndef __MACH__
--					return static_cast<uae_u64>(sigcont->sp);
-+				};
-+				const auto get_base_x = [&](const int reg) -> uae_u64 {
-+					if (reg == 31) {
-+#if defined(__FreeBSD__) && defined(CPU_AARCH64)
-+						return static_cast<uae_u64>(sigcont->mc_gpregs.gp_sp);
-+#elif !defined(__MACH__)
-+						return static_cast<uae_u64>(sigcont->sp);
- #else
--					return static_cast<uae_u64>(sigcont->__ss.__sp);
-+						return static_cast<uae_u64>(sigcont->__ss.__sp);
- #endif
--				}
--				return get_reg_x(reg);
--			};
--			const auto set_reg_w = [&](const int reg, const uae_u32 value) {
--				if (reg == 31)
--					return;
--#ifndef __MACH__
--				sigcont->regs[reg] = value;
-+					}
-+					return get_reg_x(reg);
-+				};
-+				const auto set_reg_w = [&](const int reg, const uae_u32 value) {
-+					if (reg == 31)
-+						return;
-+#if defined(__FreeBSD__) && defined(CPU_AARCH64)
-+					if (reg < 30)
-+						sigcont->mc_gpregs.gp_x[reg] = value;
-+					else
-+						sigcont->mc_gpregs.gp_lr = value;
-+#elif !defined(__MACH__)
-+					sigcont->regs[reg] = value;
- #else
--				sigcont->__ss.__x[reg] = value;
-+					sigcont->__ss.__x[reg] = value;
- #endif
--			};
-+				};
+ #define output_log write_log
+@@ -583,9 +583,9 @@ enum type_size_t {
+ 	SIZE_INT
+ };
  
- 			// Decode memory operands for additional diagnostics.
- 			const int rd = opcode & 0x1f;
-@@ -489,7 +513,9 @@ static int handle_exception(mcontext_t sigcont, long f
- 				}
+-enum style_type_t { 
+-  STYLE_SIGNED, 
+-  STYLE_UNSIGNED 
++enum style_type_t {
++  STYLE_SIGNED,
++  STYLE_UNSIGNED
+ };
  
- 				// Go to next instruction
--#ifndef __MACH__
-+#if defined(__FreeBSD__) && defined(CPU_AARCH64)
-+				sigcont->mc_gpregs.gp_elr += 4;
-+#elif !defined(__MACH__)
- 				sigcont->pc += 4;
- #else
- 				sigcont->__ss.__pc += 4;
-@@ -557,10 +583,14 @@ void signal_segv(int signum, siginfo_t* info, void* pt
+ #define HANDLE_EXCEPTION_NONE 0
+@@ -593,7 +593,7 @@ static int in_handler = 0;
+ #define HANDLE_EXCEPTION_A4000RAM 2
  
- #ifndef __MACH__
- 	mcontext_t* context = &(ucontext->uc_mcontext);
--	unsigned long long* regs = context->regs;
-+#if defined(__FreeBSD__) && defined(CPU_AARCH64)
-+	[[maybe_unused]] unsigned long long* regs = reinterpret_cast<unsigned long long*>(context->mc_gpregs.gp_x);
- #else
-+	[[maybe_unused]] unsigned long long* regs = context->regs;
-+#endif
-+#else
- 	mcontext_t context = ucontext->uc_mcontext;
--	unsigned long long* regs = context->__ss.__x;
-+	[[maybe_unused]] unsigned long long* regs = context->__ss.__x;
*** 386 LINES SKIPPED ***