]> gitweb.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
cmake: own the qemu-uae plugin provisioning
authorStefan Reinauer <stefan.reinauer@coreboot.org>
Fri, 12 Jun 2026 05:57:19 +0000 (22:57 -0700)
committerStefan Reinauer <stefan.reinauer@coreboot.org>
Tue, 7 Jul 2026 20:59:15 +0000 (13:59 -0700)
The mandatory qemu-uae.so plugin was only buildable from a sibling
qemu-uae source tree; distro builds without one configured fine, built
fine, and then failed at install time when the install rule referenced
the never-built plugin (GitHub issue #6). Both CI workflows carried
their own duplicated checkout/build/strip plumbing for the
uae-ppc-plugin builder instead.

Resolve the plugin at configure time, in order: prebuilt
WINUAE_QEMU_UAE_PLUGIN_FILE, the sibling qemu-uae source tree, an
uae-ppc-plugin builder checkout (WINUAE_QEMU_UAE_BUILDER_DIR, default
sibling; WINUAE_QEMU_UAE_QEMU_TARBALL feeds it a local QEMU tarball for
offline distribution builds), or a build-time clone of the builder
(WINUAE_QEMU_UAE_BUILDER_FETCH, default ON). When nothing applies the
configure fails with the list of options. On Linux the plugin target is
part of the default build so plain build+install flows always bundle
the plugin.

Drive the builder through an OUTPUT-based custom command so repeated
`all` builds and CPack preinstall do not rerun the external builder once
qemu-uae.so is already present.

The Ubuntu and macOS workflows drop their manual plugin build steps and
pass the builder checkout to CMake; stripping moved into the builder
wrapper script.

CMakeLists.txt
README_unix.md
tools/build-qemu-uae-via-builder.sh [new file with mode: 0755]

index 8bb901ae089d1c412c59489464fb921a88dd1eaf..640eff199a193311b2328122dbfb241c8c802def 100644 (file)
@@ -208,6 +208,13 @@ set(WINUAE_LZMA_SDK_SYSTEM_PATHS
 set(WINUAE_QEMU_UAE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../qemu-uae-v11.0"
     CACHE PATH "QEMU-UAE plugin source directory")
 set(WINUAE_QEMU_UAE_PLUGIN_FILE "" CACHE FILEPATH "Prebuilt qemu-uae.so plugin to install or bundle")
+set(WINUAE_QEMU_UAE_BUILDER_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../uae-ppc-plugin"
+    CACHE PATH "uae-ppc-plugin builder checkout used to build qemu-uae.so")
+set(WINUAE_QEMU_UAE_BUILDER_URL "https://github.com/reinauer/uae-ppc-plugin.git"
+    CACHE STRING "Git URL cloned at build time when the builder checkout is missing")
+option(WINUAE_QEMU_UAE_BUILDER_FETCH "Clone the uae-ppc-plugin builder when no local copy is found" ON)
+set(WINUAE_QEMU_UAE_QEMU_TARBALL "" CACHE FILEPATH
+    "Local QEMU source tarball for offline qemu-uae plugin builds")
 set(WINUAE_UNIX_INSTALL_PLUGINDIR_RELATIVE "${CMAKE_INSTALL_LIBDIR}/winuae/plugins"
     CACHE STRING "Relative Unix install directory for runtime plugins")
 
@@ -1703,30 +1710,84 @@ if(WINUAE_QEMU_UAE_PLUGIN_FILE)
 else()
     set(WINUAE_QEMU_UAE_PLUGIN_PATH "${CMAKE_BINARY_DIR}/qemu-uae.so")
 endif()
+# On Linux the plugin is part of the default build so that plain
+# `cmake --build` + `cmake --install` flows (distro packaging) always
+# produce the mandatory qemu-uae.so. macOS keeps it behind the app/dmg
+# and package targets.
+set(WINUAE_QEMU_UAE_PLUGIN_ALL)
+if(UNIX AND NOT APPLE)
+    set(WINUAE_QEMU_UAE_PLUGIN_ALL ALL)
+endif()
 if(UNIX
     AND WINUAE_UNIX_WITH_PPC_QEMU
     AND WINUAE_UNIX_BUILD_QEMU_UAE_PLUGIN
-    AND EXISTS "${WINUAE_QEMU_UAE_SOURCE_DIR}/configure-qemu-uae")
-    add_custom_target(winuae_unix_qemu_uae_plugin
-        COMMAND "${CMAKE_COMMAND}" -E env
-            "WINUAE_MACOS_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}"
-            "QEMU_UAE_DEPS_PREFIX=${WINUAE_QEMU_UAE_DEPS_PREFIX}"
-            "${CMAKE_CURRENT_SOURCE_DIR}/tools/build-qemu-uae.sh"
-            "${WINUAE_QEMU_UAE_SOURCE_DIR}"
-            "${WINUAE_QEMU_UAE_PLUGIN_PATH}"
-        WORKING_DIRECTORY "${WINUAE_QEMU_UAE_SOURCE_DIR}"
-        COMMENT "Building QEMU-UAE PPC plugin"
-        VERBATIM
-    )
+    AND NOT WINUAE_QEMU_UAE_PLUGIN_FILE)
+    if(EXISTS "${WINUAE_QEMU_UAE_SOURCE_DIR}/configure-qemu-uae")
+        message(STATUS
+            "QEMU-UAE plugin: building from sibling source ${WINUAE_QEMU_UAE_SOURCE_DIR}")
+        add_custom_target(winuae_unix_qemu_uae_plugin ${WINUAE_QEMU_UAE_PLUGIN_ALL}
+            COMMAND "${CMAKE_COMMAND}" -E env
+                "WINUAE_MACOS_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}"
+                "QEMU_UAE_DEPS_PREFIX=${WINUAE_QEMU_UAE_DEPS_PREFIX}"
+                "${CMAKE_CURRENT_SOURCE_DIR}/tools/build-qemu-uae.sh"
+                "${WINUAE_QEMU_UAE_SOURCE_DIR}"
+                "${WINUAE_QEMU_UAE_PLUGIN_PATH}"
+            WORKING_DIRECTORY "${WINUAE_QEMU_UAE_SOURCE_DIR}"
+            COMMENT "Building QEMU-UAE PPC plugin"
+            VERBATIM
+        )
+    elseif(EXISTS "${WINUAE_QEMU_UAE_BUILDER_DIR}/build-qemu-uae-plugin.sh"
+        OR WINUAE_QEMU_UAE_BUILDER_FETCH)
+        if(EXISTS "${WINUAE_QEMU_UAE_BUILDER_DIR}/build-qemu-uae-plugin.sh")
+            message(STATUS
+                "QEMU-UAE plugin: building through ${WINUAE_QEMU_UAE_BUILDER_DIR}")
+        else()
+            message(STATUS
+                "QEMU-UAE plugin: builder will be cloned from ${WINUAE_QEMU_UAE_BUILDER_URL}")
+        endif()
+        # OUTPUT-based so repeated `all` builds (e.g. the CPack preinstall
+        # step) skip the builder once the plugin exists; the external
+        # builder's configure step is not re-entrant.
+        add_custom_command(OUTPUT "${WINUAE_QEMU_UAE_PLUGIN_PATH}"
+            COMMAND "${CMAKE_COMMAND}" -E env
+                "WINUAE_MACOS_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}"
+                "QEMU_UAE_DEPS_PREFIX=${WINUAE_QEMU_UAE_DEPS_PREFIX}"
+                "QEMU_UAE_WORK_DIR=${CMAKE_BINARY_DIR}/_deps/qemu-uae"
+                "WINUAE_QEMU_UAE_BUILDER_DIR=${WINUAE_QEMU_UAE_BUILDER_DIR}"
+                "WINUAE_QEMU_UAE_BUILDER_URL=${WINUAE_QEMU_UAE_BUILDER_URL}"
+                "WINUAE_QEMU_UAE_BUILDER_FETCH=$<BOOL:${WINUAE_QEMU_UAE_BUILDER_FETCH}>"
+                "WINUAE_QEMU_UAE_QEMU_TARBALL=${WINUAE_QEMU_UAE_QEMU_TARBALL}"
+                "${CMAKE_CURRENT_SOURCE_DIR}/tools/build-qemu-uae-via-builder.sh"
+                "${WINUAE_QEMU_UAE_PLUGIN_PATH}"
+            DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/tools/build-qemu-uae-via-builder.sh"
+            WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+            COMMENT "Building QEMU-UAE PPC plugin through uae-ppc-plugin"
+            VERBATIM
+        )
+        add_custom_target(winuae_unix_qemu_uae_plugin ${WINUAE_QEMU_UAE_PLUGIN_ALL}
+            DEPENDS "${WINUAE_QEMU_UAE_PLUGIN_PATH}"
+        )
+    endif()
 endif()
 
-if(WINUAE_UNIX_WITH_PPC_QEMU)
+if(UNIX AND WINUAE_UNIX_WITH_PPC_QEMU)
     if(WINUAE_QEMU_UAE_PLUGIN_FILE)
         if(NOT EXISTS "${WINUAE_QEMU_UAE_PLUGIN_PATH}")
             message(FATAL_ERROR
                 "WINUAE_QEMU_UAE_PLUGIN_FILE does not exist: "
                 "${WINUAE_QEMU_UAE_PLUGIN_PATH}")
         endif()
+        message(STATUS
+            "QEMU-UAE plugin: using prebuilt ${WINUAE_QEMU_UAE_PLUGIN_PATH}")
+    elseif(NOT TARGET winuae_unix_qemu_uae_plugin)
+        message(FATAL_ERROR
+            "WINUAE_UNIX_WITH_PPC_QEMU requires the QEMU-UAE PPC plugin, but no "
+            "way to provide qemu-uae.so was found. Provide one of:\n"
+            "  -DWINUAE_QEMU_UAE_PLUGIN_FILE=/path/to/qemu-uae.so (prebuilt plugin)\n"
+            "  -DWINUAE_QEMU_UAE_BUILDER_DIR=/path/to/uae-ppc-plugin (builder checkout; "
+            "offline builds also want -DWINUAE_QEMU_UAE_QEMU_TARBALL=/path/to/qemu-11.0.1.tar.xz)\n"
+            "  -DWINUAE_QEMU_UAE_BUILDER_FETCH=ON to clone ${WINUAE_QEMU_UAE_BUILDER_URL} at build time\n"
+            "  a qemu-uae source tree at ${WINUAE_QEMU_UAE_SOURCE_DIR}")
     endif()
     set(WINUAE_UNIX_QEMU_UAE_PACKAGE_CHECK_DEPS)
     if(TARGET winuae_unix_qemu_uae_plugin)
index 368114d9e00ab8f969dbd3c92649221225e2f4c4..37092b872b61f4fed1d1abdcd200cde2e84894cd 100644 (file)
@@ -184,17 +184,29 @@ when found under `WINUAE_LZMA_SDK_SYSTEM_PATHS` (or an explicit
 SHA-verified `lzma1604.7z` archive. Pass `-DWINUAE_LZMA_SDK_FETCH=OFF` for
 offline distribution builds.
 
-To build a package from a prebuilt QEMU-UAE plugin, pass:
-
-```sh
-tools/debian-build-package.sh -- \
-  -DWINUAE_QEMU_UAE_PLUGIN_FILE=/path/to/qemu-uae.so \
-  -DWINUAE_UNIX_BUILD_QEMU_UAE_PLUGIN=OFF
-```
-
-Package builds fail when `WINUAE_UNIX_WITH_PPC_QEMU=ON` and the resolved
-`qemu-uae.so` path does not exist. Disable `WINUAE_UNIX_WITH_PPC_QEMU` for a
-deliberately reduced package without PPC plugin support.
+The `qemu-uae.so` PPC plugin is a mandatory part of Unix packages. CMake
+resolves it at configure time, in this order, and fails the configure with
+instructions when none applies:
+
+1. `-DWINUAE_QEMU_UAE_PLUGIN_FILE=/path/to/qemu-uae.so` — a prebuilt plugin.
+2. A patched `qemu-uae` source tree at `WINUAE_QEMU_UAE_SOURCE_DIR`
+   (default: sibling `../qemu-uae-v11.0`) — the developer path.
+3. The `uae-ppc-plugin` builder at `WINUAE_QEMU_UAE_BUILDER_DIR`
+   (default: sibling `../uae-ppc-plugin`). The builder downloads a
+   SHA-verified QEMU source tarball, applies the UAE patch deck, and builds
+   the plugin during the WinUAE build. For offline builds (distribution
+   packaging), declare the QEMU tarball as a package source and pass
+   `-DWINUAE_QEMU_UAE_QEMU_TARBALL=/path/to/qemu-11.0.1.tar.xz`.
+4. When no builder checkout is found and `WINUAE_QEMU_UAE_BUILDER_FETCH` is
+   `ON` (the default), the builder is cloned at build time from
+   `WINUAE_QEMU_UAE_BUILDER_URL`.
+
+On Linux the plugin target is part of the default build, so plain
+`cmake --build` + `cmake --install` flows always produce and install the
+plugin. A distribution package build needs `meson`, `ninja`, GLib and libfdt
+development headers for the embedded QEMU build, plus the builder checkout
+and QEMU tarball as additional sources when the build host has no network
+access.
 
 The Linux install/package metadata can be checked on any Unix host:
 
@@ -280,11 +292,14 @@ CMake also exposes this as:
 cmake --build /tmp/winuae_cmake_build --target winuae_unix_qemu_uae_plugin -j
 ```
 
-`WINUAE_UNIX_BUILD_QEMU_UAE_PLUGIN` controls whether the sibling plugin target
+`WINUAE_UNIX_BUILD_QEMU_UAE_PLUGIN` controls whether the plugin build target
 is enabled, and `WINUAE_QEMU_UAE_SOURCE_DIR` can point at a different
 `qemu-uae` source tree. `WINUAE_QEMU_UAE_PLUGIN_FILE` can point at an already
-built plugin, which is useful for CI jobs that build the plugin through the
-release-oriented `uae-ppc-plugin` wrapper. `WINUAE_QEMU_UAE_DEPS_PREFIX`
+built plugin. Without a patched source tree, the target builds through the
+release-oriented `uae-ppc-plugin` builder (`WINUAE_QEMU_UAE_BUILDER_DIR`,
+cloned from `WINUAE_QEMU_UAE_BUILDER_URL` when missing and
+`WINUAE_QEMU_UAE_BUILDER_FETCH` is enabled; `WINUAE_QEMU_UAE_QEMU_TARBALL`
+supplies a local QEMU tarball for offline builds). `WINUAE_QEMU_UAE_DEPS_PREFIX`
 defaults to the private macOS dependency prefix and is passed to the plugin
 helper as `QEMU_UAE_DEPS_PREFIX`. Set `QEMU_UAE_NINJA=/path/to/ninja` if QEMU
 configure cannot find Ninja itself. On macOS, the app bundler copies
diff --git a/tools/build-qemu-uae-via-builder.sh b/tools/build-qemu-uae-via-builder.sh
new file mode 100755 (executable)
index 0000000..ea70f39
--- /dev/null
@@ -0,0 +1,81 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+usage() {
+    cat <<EOF
+Usage: $0 <output-plugin>
+
+Builds qemu-uae.so through the external uae-ppc-plugin builder, which
+downloads a SHA-verified QEMU source tarball (or uses a local one),
+applies the UAE patch deck, and builds the plugin.
+
+Environment:
+  WINUAE_QEMU_UAE_BUILDER_DIR    uae-ppc-plugin checkout. When missing and
+                                 fetching is allowed, it is cloned.
+  WINUAE_QEMU_UAE_BUILDER_URL    Clone URL. Defaults to the reinauer repo.
+  WINUAE_QEMU_UAE_BUILDER_FETCH  0 disables cloning a missing builder.
+  WINUAE_QEMU_UAE_BUILDER_CLONE_DIR
+                                 Clone destination. Defaults to
+                                 <work-dir>/uae-ppc-plugin.
+  WINUAE_QEMU_UAE_QEMU_TARBALL   Local QEMU source tarball for offline
+                                 builds; passed to the builder as --tarball.
+  WINUAE_QEMU_UAE_STRIP          0 keeps symbols in the built plugin.
+  QEMU_UAE_WORK_DIR              Builder working directory.
+  QEMU_UAE_DEPS_PREFIX           Private GLib/libslirp dependency prefix.
+  WINUAE_MACOS_DEPLOYMENT_TARGET macOS deployment target for the plugin.
+EOF
+}
+
+if [[ "${1:-}" == "-h" || "${1:-}" == "--help" || $# -lt 1 ]]; then
+    usage
+    [[ $# -lt 1 ]] && exit 2
+    exit 0
+fi
+
+output_plugin="$1"
+builder_dir="${WINUAE_QEMU_UAE_BUILDER_DIR:-}"
+builder_url="${WINUAE_QEMU_UAE_BUILDER_URL:-https://github.com/reinauer/uae-ppc-plugin.git}"
+builder_fetch="${WINUAE_QEMU_UAE_BUILDER_FETCH:-1}"
+work_dir="${QEMU_UAE_WORK_DIR:-$(pwd)/qemu-uae-work}"
+clone_dir="${WINUAE_QEMU_UAE_BUILDER_CLONE_DIR:-${work_dir}/uae-ppc-plugin}"
+tarball="${WINUAE_QEMU_UAE_QEMU_TARBALL:-}"
+
+builder_script() {
+    printf '%s/build-qemu-uae-plugin.sh' "$1"
+}
+
+if [[ -z "${builder_dir}" || ! -x "$(builder_script "${builder_dir}")" ]]; then
+    if [[ -x "$(builder_script "${clone_dir}")" ]]; then
+        builder_dir="${clone_dir}"
+    elif [[ "${builder_fetch}" != "0" ]]; then
+        echo "Cloning QEMU-UAE plugin builder from ${builder_url}"
+        mkdir -p "$(dirname "${clone_dir}")"
+        git clone --depth 1 "${builder_url}" "${clone_dir}"
+        builder_dir="${clone_dir}"
+    else
+        echo "error: uae-ppc-plugin builder not found" >&2
+        echo "hint: set WINUAE_QEMU_UAE_BUILDER_DIR to a checkout of" >&2
+        echo "      ${builder_url}, or allow cloning" >&2
+        exit 1
+    fi
+fi
+
+args=( --output "${output_plugin}" )
+if [[ -n "${tarball}" ]]; then
+    if [[ ! -f "${tarball}" ]]; then
+        echo "error: WINUAE_QEMU_UAE_QEMU_TARBALL does not exist: ${tarball}" >&2
+        exit 1
+    fi
+    args+=( --tarball "${tarball}" )
+fi
+
+export QEMU_UAE_WORK_DIR="${work_dir}"
+"$(builder_script "${builder_dir}")" "${args[@]}"
+
+if [[ "${WINUAE_QEMU_UAE_STRIP:-1}" != "0" ]]; then
+    if [[ "$(uname -s)" == "Darwin" ]]; then
+        strip -x "${output_plugin}"
+    else
+        strip --strip-unneeded "${output_plugin}"
+    fi
+fi