git: 4c297a965923 - main - emulators/amiberry: update to 8.3.0
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
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 ***