From bba6a8d38f43069b7e1659c9a01cee7913aaa45b Mon Sep 17 00:00:00 2001 From: Stefan Reinauer Date: Thu, 4 Jun 2026 07:59:36 -0700 Subject: [PATCH] tools: add macOS packaging helpers Add helpers for building private macOS dependencies, bundling the app, building the QEMU-PPC plugin, creating the DMG, and validating output. This keeps the release packaging flow reproducible outside local shell history. --- od-unix/graphics/dmg_background.tiff | Bin 0 -> 80062 bytes tools/build-qemu-uae.sh | 83 ++++++ tools/macos-build-deps.sh | 394 +++++++++++++++++++++++++ tools/macos-build-qemu-deps.sh | 185 ++++++++++++ tools/macos-bundle.sh | 326 ++++++++++++++++++++ tools/macos-check-deployment-target.sh | 93 ++++++ tools/macos-dmg.sh | 231 +++++++++++++++ tools/macos-smoke-app.sh | 123 ++++++++ tools/macos-verify-dmg.sh | 148 ++++++++++ 9 files changed, 1583 insertions(+) create mode 100644 od-unix/graphics/dmg_background.tiff create mode 100755 tools/build-qemu-uae.sh create mode 100755 tools/macos-build-deps.sh create mode 100755 tools/macos-build-qemu-deps.sh create mode 100755 tools/macos-bundle.sh create mode 100755 tools/macos-check-deployment-target.sh create mode 100755 tools/macos-dmg.sh create mode 100755 tools/macos-smoke-app.sh create mode 100755 tools/macos-verify-dmg.sh diff --git a/od-unix/graphics/dmg_background.tiff b/od-unix/graphics/dmg_background.tiff new file mode 100644 index 0000000000000000000000000000000000000000..4da049aa80ec0c13b73c43760b3a221445a1fbf8 GIT binary patch literal 80062 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 c^80*W?B@+u{~_p!4Aya<&2 + exit 1 +fi +qemu_source="$(cd "${qemu_source}" && pwd)" + +if [[ "$(uname -s)" == "Darwin" ]]; then + export MACOSX_DEPLOYMENT_TARGET="${WINUAE_MACOS_DEPLOYMENT_TARGET:-${MACOSX_DEPLOYMENT_TARGET:-13.0}}" +fi + +if [[ -n "${deps_prefix}" ]]; then + if [[ ! -d "${deps_prefix}" ]]; then + echo "error: QEMU_UAE_DEPS_PREFIX does not exist: ${deps_prefix}" >&2 + exit 1 + fi + 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}}" + if [[ "$(uname -s)" == "Darwin" ]]; then + export DYLD_LIBRARY_PATH="${deps_prefix}/lib${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}}" + fi +fi + +ninja_executable="${QEMU_UAE_NINJA:-$(command -v ninja || true)}" +if [[ -z "${ninja_executable}" && -x "${qemu_source}/build/pyvenv/bin/ninja" ]]; then + ninja_executable="${qemu_source}/build/pyvenv/bin/ninja" +fi +if [[ -z "${ninja_executable}" ]]; then + echo "error: ninja not found; set QEMU_UAE_NINJA" >&2 + exit 1 +fi + +if [[ "${QEMU_UAE_SKIP_CONFIGURE:-0}" != "1" && ( "${QEMU_UAE_FORCE_CONFIGURE:-0}" == "1" || ! -f "${qemu_source}/build/build.ninja" ) ]]; then + (cd "${qemu_source}" && ./configure-qemu-uae --ninja="${ninja_executable}") +fi + +"${ninja_executable}" -C "${qemu_source}/build" qemu-uae.so + +plugin="${qemu_source}/build/qemu-uae.so" +if [[ ! -f "${plugin}" ]]; then + echo "error: qemu-uae.so was not produced" >&2 + exit 1 +fi + +if [[ -n "${output_plugin}" ]]; then + mkdir -p "$(dirname "${output_plugin}")" + cp "${plugin}" "${output_plugin}" + plugin="${output_plugin}" +fi + +echo "${plugin}" diff --git a/tools/macos-build-deps.sh b/tools/macos-build-deps.sh new file mode 100755 index 00000000..283dff6b --- /dev/null +++ b/tools/macos-build-deps.sh @@ -0,0 +1,394 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat </../winuae-macos-deps. + +Environment: + WINUAE_MACOS_DEPLOYMENT_TARGET Minimum macOS version. Defaults to 13.0. + WINUAE_DEPS_BUILD_DIR Build directory. Defaults to /build. + WINUAE_DEPS_JOBS Parallel build jobs. Defaults to hw.ncpu. + WINUAE_SDL3_SOURCE SDL3 source tree. Required unless + WINUAE_SKIP_SDL3=1. + WINUAE_QT_SOURCE Qt 6 source tree, or a qtbase CMake source + tree. Required unless WINUAE_SKIP_QT=1. + WINUAE_LIBPNG_SOURCE libpng source tree. Optional unless + WINUAE_REQUIRE_LIBPNG=1. + WINUAE_FLAC_SOURCE FLAC source tree. Optional unless + WINUAE_REQUIRE_FLAC=1. + WINUAE_LIBMPEG2_SOURCE libmpeg2 source tree. Optional unless + WINUAE_REQUIRE_LIBMPEG2=1. + WINUAE_MT32EMU_SOURCE Munt source tree or mt32emu source tree. + Optional unless WINUAE_REQUIRE_MT32EMU=1. + WINUAE_SKIP_SDL3=1 Do not build SDL3. + WINUAE_SKIP_QT=1 Do not build Qt. + WINUAE_SKIP_LIBPNG=1 Do not build libpng. + WINUAE_SKIP_FLAC=1 Do not build libFLAC. + WINUAE_SKIP_LIBMPEG2=1 Do not build libmpeg2. + WINUAE_SKIP_MT32EMU=1 Do not build libmt32emu. + WINUAE_REQUIRE_LIBPNG=1 Fail if WINUAE_LIBPNG_SOURCE is missing. + WINUAE_REQUIRE_FLAC=1 Fail if WINUAE_FLAC_SOURCE is missing. + WINUAE_REQUIRE_LIBMPEG2=1 Fail if WINUAE_LIBMPEG2_SOURCE is missing. + WINUAE_REQUIRE_MT32EMU=1 Fail if WINUAE_MT32EMU_SOURCE is missing. + WINUAE_SDL3_CMAKE_ARGS Extra arguments passed to SDL3 CMake. + WINUAE_QT_CONFIGURE_ARGS Extra arguments passed to Qt configure, + in addition to the release-safe defaults. + WINUAE_QT_CMAKE_ARGS Extra arguments passed to Qt CMake. + WINUAE_LIBPNG_CMAKE_ARGS Extra arguments passed to libpng CMake. + WINUAE_FLAC_CMAKE_ARGS Extra arguments passed to FLAC CMake. + WINUAE_LIBMPEG2_CONFIGURE_ARGS Extra arguments passed to libmpeg2 configure. + WINUAE_MT32EMU_CMAKE_ARGS Extra arguments passed to mt32emu CMake. + +Extra argument variables are whitespace-separated argv fragments. +EOF +} + +if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then + usage + exit 0 +fi + +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source_dir="$(cd "${script_dir}/.." && pwd)" +target="${WINUAE_MACOS_DEPLOYMENT_TARGET:-13.0}" +prefix="${1:-${WINUAE_DEPS_PREFIX:-${source_dir}/../winuae-macos-deps}}" +build_dir="${WINUAE_DEPS_BUILD_DIR:-${prefix}/build}" +sdl_source="${WINUAE_SDL3_SOURCE:-}" +qt_source="${WINUAE_QT_SOURCE:-}" +libpng_source="${WINUAE_LIBPNG_SOURCE:-}" +flac_source="${WINUAE_FLAC_SOURCE:-}" +libmpeg2_source="${WINUAE_LIBMPEG2_SOURCE:-}" +mt32emu_source="${WINUAE_MT32EMU_SOURCE:-}" + +if [[ "$(uname -s)" != "Darwin" ]]; then + echo "error: macOS dependency builds require Darwin/macOS" >&2 + exit 1 +fi + +jobs="${WINUAE_DEPS_JOBS:-}" +if [[ -z "${jobs}" ]]; then + jobs="$(sysctl -n hw.ncpu 2>/dev/null || echo 8)" +fi +export MACOSX_DEPLOYMENT_TARGET="${target}" + +require_source() { + local name="$1" + local path="$2" + if [[ -z "${path}" ]]; then + echo "error: ${name} source path is required" >&2 + usage >&2 + exit 1 + fi + if [[ ! -d "${path}" ]]; then + echo "error: ${name} source directory not found: ${path}" >&2 + exit 1 + fi +} + +run_cmake_build() { + local src="$1" + local bld="$2" + shift 2 + cmake -S "${src}" -B "${bld}" "$@" + cmake --build "${bld}" -j "${jobs}" + cmake --install "${bld}" +} + +run_autotools_build() { + local src="$1" + local bld="$2" + shift 2 + if [[ -z "${bld}" || "${bld}" == "/" ]]; then + echo "error: refusing unsafe autotools build directory: ${bld}" >&2 + exit 1 + fi + rm -rf "${bld}" + mkdir -p "${bld}/src" + cp -R "${src}/." "${bld}/src/" + ( + cd "${bld}/src" + if [[ -f Makefile ]]; then + make distclean >/dev/null 2>&1 || true + fi + rm -f config.log config.status + env \ + CFLAGS="${CFLAGS:-} -mmacosx-version-min=${target}" \ + CXXFLAGS="${CXXFLAGS:-} -mmacosx-version-min=${target}" \ + LDFLAGS="${LDFLAGS:-} -mmacosx-version-min=${target}" \ + ./configure "$@" + make -j "${jobs}" + make install + ) +} + +patch_qtbase_source() { + local header="${qt_source}/src/corelib/thread/qyieldcpu.h" + if [[ -f "${header}" ]] && grep -q "__yield();" "${header}" && ! grep -q "arm_acle.h" "${header}"; then + perl -0pi -e 's/(#include \n)/$1\n#if defined(__has_include)\n# if __has_include()\n# include \n# endif\n#endif\n/' "${header}" + fi + + local simd="${qt_source}/src/corelib/global/qsimd.cpp" + if [[ -f "${simd}" ]] && grep -q 'sysctlbyname("hw.optional.neon"' "${simd}" && ! grep -q "AArch64 includes Advanced SIMD" "${simd}"; then + perl -0pi -e 's/#elif defined\(Q_OS_DARWIN\) && defined\(Q_PROCESSOR_ARM\)\n unsigned feature;\n size_t len = sizeof\(feature\);\n if \(sysctlbyname\("hw\.optional\.neon", &feature, &len, nullptr, 0\) == 0\)\n features \|= feature \? CpuFeatureNEON : 0;/#elif defined(Q_OS_DARWIN) \&\& defined(Q_PROCESSOR_ARM)\n unsigned feature;\n size_t len = sizeof(feature);\n# if defined(Q_PROCESSOR_ARM_64)\n \/\/ AArch64 includes Advanced SIMD; some macOS versions no longer\n \/\/ expose the legacy hw.optional.neon sysctl that Qt probes here.\n features |= CpuFeatureNEON;\n# else\n if (sysctlbyname("hw.optional.neon", \&feature, \&len, nullptr, 0) == 0)\n features |= feature ? CpuFeatureNEON : 0;\n# endif/' "${simd}" + fi +} + +split_extra_args() { + extra_args=() + if [[ -n "${1:-}" ]]; then + # Extra-arg variables are whitespace-separated argv fragments. + # Split once here and pass the result as an array at call sites. + # shellcheck disable=SC2206 + extra_args=($1) + fi +} + +mkdir -p "${prefix}" "${build_dir}" + +if [[ "${WINUAE_SKIP_LIBPNG:-0}" != "1" ]]; then + if [[ -n "${libpng_source}" ]]; then + require_source "libpng" "${libpng_source}" + libpng_cmake_args=( + -DCMAKE_BUILD_TYPE=Release + -DCMAKE_INSTALL_PREFIX="${prefix}" + -DCMAKE_OSX_DEPLOYMENT_TARGET="${target}" + -DPNG_SHARED=ON + -DPNG_STATIC=OFF + -DPNG_TESTS=OFF + -DPNG_TOOLS=OFF + ) + split_extra_args "${WINUAE_LIBPNG_CMAKE_ARGS:-}" + libpng_cmake_args+=(${extra_args[@]+"${extra_args[@]}"}) + run_cmake_build "${libpng_source}" "${build_dir}/libpng" \ + "${libpng_cmake_args[@]}" + elif [[ "${WINUAE_REQUIRE_LIBPNG:-0}" == "1" ]]; then + echo "error: libpng source path is required when WINUAE_REQUIRE_LIBPNG=1" >&2 + usage >&2 + exit 1 + else + echo "note: WINUAE_LIBPNG_SOURCE not set; skipping private libpng build" >&2 + fi +fi + +if [[ "${WINUAE_SKIP_FLAC:-0}" != "1" ]]; then + if [[ -n "${flac_source}" ]]; then + require_source "FLAC" "${flac_source}" + flac_cmake_args=( + -DCMAKE_BUILD_TYPE=Release + -DCMAKE_INSTALL_PREFIX="${prefix}" + -DCMAKE_OSX_DEPLOYMENT_TARGET="${target}" + -DBUILD_SHARED_LIBS=ON + -DBUILD_CXXLIBS=OFF + -DBUILD_PROGRAMS=OFF + -DBUILD_EXAMPLES=OFF + -DBUILD_DOCS=OFF + -DBUILD_TESTING=OFF + -DINSTALL_MANPAGES=OFF + -DINSTALL_PKGCONFIG_MODULES=ON + -DWITH_OGG=OFF + ) + split_extra_args "${WINUAE_FLAC_CMAKE_ARGS:-}" + flac_cmake_args+=(${extra_args[@]+"${extra_args[@]}"}) + run_cmake_build "${flac_source}" "${build_dir}/flac" \ + "${flac_cmake_args[@]}" + elif [[ "${WINUAE_REQUIRE_FLAC:-0}" == "1" ]]; then + echo "error: FLAC source path is required when WINUAE_REQUIRE_FLAC=1" >&2 + usage >&2 + exit 1 + else + echo "note: WINUAE_FLAC_SOURCE not set; skipping private libFLAC build" >&2 + fi +fi + +if [[ "${WINUAE_SKIP_LIBMPEG2:-0}" != "1" ]]; then + if [[ -n "${libmpeg2_source}" ]]; then + require_source "libmpeg2" "${libmpeg2_source}" + libmpeg2_configure_args=( + --prefix="${prefix}" + --disable-sdl + --without-x + --enable-shared + --disable-static + --disable-dependency-tracking + ) + if [[ -n "${WINUAE_LIBMPEG2_CONFIGURE_ARGS:-}" ]]; then + split_extra_args "${WINUAE_LIBMPEG2_CONFIGURE_ARGS}" + libmpeg2_configure_args+=(${extra_args[@]+"${extra_args[@]}"}) + fi + run_autotools_build "${libmpeg2_source}" "${build_dir}/libmpeg2" \ + "${libmpeg2_configure_args[@]}" + ( + cd "${build_dir}/libmpeg2/src" + make -C libmpeg2 install + make -C include install + ) + elif [[ "${WINUAE_REQUIRE_LIBMPEG2:-0}" == "1" ]]; then + echo "error: libmpeg2 source path is required when WINUAE_REQUIRE_LIBMPEG2=1" >&2 + usage >&2 + exit 1 + else + echo "note: WINUAE_LIBMPEG2_SOURCE not set; skipping private libmpeg2 build" >&2 + fi +fi + +if [[ "${WINUAE_SKIP_MT32EMU:-0}" != "1" ]]; then + if [[ -n "${mt32emu_source}" ]]; then + require_source "Munt/mt32emu" "${mt32emu_source}" + mt32emu_cmake_source="${mt32emu_source}" + if [[ -f "${mt32emu_source}/mt32emu/CMakeLists.txt" ]]; then + mt32emu_cmake_source="${mt32emu_source}/mt32emu" + fi + if [[ ! -f "${mt32emu_cmake_source}/CMakeLists.txt" ]]; then + echo "error: mt32emu CMakeLists.txt not found under ${mt32emu_source}" >&2 + exit 1 + fi + mt32emu_cmake_args=( + -DCMAKE_BUILD_TYPE=Release + -DCMAKE_INSTALL_PREFIX="${prefix}" + -DCMAKE_OSX_DEPLOYMENT_TARGET="${target}" + -DBUILD_TESTING=OFF + -Dlibmt32emu_SHARED=ON + -Dlibmt32emu_C_INTERFACE=ON + -Dlibmt32emu_CPP_INTERFACE=OFF + -Dlibmt32emu_WITH_INTERNAL_RESAMPLER=ON + ) + split_extra_args "${WINUAE_MT32EMU_CMAKE_ARGS:-}" + mt32emu_cmake_args+=(${extra_args[@]+"${extra_args[@]}"}) + run_cmake_build "${mt32emu_cmake_source}" "${build_dir}/mt32emu" \ + "${mt32emu_cmake_args[@]}" + elif [[ "${WINUAE_REQUIRE_MT32EMU:-0}" == "1" ]]; then + echo "error: Munt/mt32emu source path is required when WINUAE_REQUIRE_MT32EMU=1" >&2 + usage >&2 + exit 1 + else + echo "note: WINUAE_MT32EMU_SOURCE not set; skipping private libmt32emu build" >&2 + fi +fi + +if [[ "${WINUAE_SKIP_SDL3:-0}" != "1" ]]; then + require_source "SDL3" "${sdl_source}" + sdl3_cmake_args=( + -DCMAKE_BUILD_TYPE=Release + -DCMAKE_INSTALL_PREFIX="${prefix}" + -DCMAKE_OSX_DEPLOYMENT_TARGET="${target}" + -DSDL_SHARED=ON + -DSDL_STATIC=OFF + -DSDL_TESTS=OFF + -DSDL_EXAMPLES=OFF + -DSDL_INSTALL_TESTS=OFF + ) + split_extra_args "${WINUAE_SDL3_CMAKE_ARGS:-}" + sdl3_cmake_args+=(${extra_args[@]+"${extra_args[@]}"}) + run_cmake_build "${sdl_source}" "${build_dir}/sdl3" \ + "${sdl3_cmake_args[@]}" +fi + +if [[ "${WINUAE_SKIP_QT:-0}" != "1" ]]; then + require_source "Qt" "${qt_source}" + qt_build="${build_dir}/qt" + mkdir -p "${qt_build}" + patch_qtbase_source + + qt_configure_args=( + -force-bundled-libs + -no-dbus + -no-openssl + -no-glib + -no-icu + -no-cups + -no-fontconfig + -no-gtk + -qt-doubleconversion + -qt-pcre + -qt-zlib + -qt-libpng + -qt-libjpeg + -qt-freetype + -qt-harfbuzz + ) + if [[ -n "${WINUAE_QT_CONFIGURE_ARGS:-}" ]]; then + split_extra_args "${WINUAE_QT_CONFIGURE_ARGS}" + qt_configure_args+=(${extra_args[@]+"${extra_args[@]}"}) + fi + + qt_cmake_args=() + if ! xcodebuild -version >/dev/null 2>&1 && xcrun --show-sdk-path >/dev/null 2>&1; then + qt_cmake_args+=(-DQT_NO_XCODE_MIN_VERSION_CHECK=ON) + fi + if [[ -n "${WINUAE_QT_CMAKE_ARGS:-}" ]]; then + split_extra_args "${WINUAE_QT_CMAKE_ARGS}" + qt_cmake_args+=(${extra_args[@]+"${extra_args[@]}"}) + fi + + qt_submodule_args=() + if [[ -d "${qt_source}/qtbase" || -f "${qt_source}/init-repository" ]]; then + qt_submodule_args=(-submodules qtbase) + fi + + if [[ -x "${qt_source}/configure" && ! -d "${qt_source}/src/corelib" ]]; then + ( + cd "${qt_build}" + "${qt_source}/configure" \ + -prefix "${prefix}" \ + -release \ + -opensource \ + -confirm-license \ + -nomake examples \ + -nomake tests \ + ${qt_submodule_args[@]+"${qt_submodule_args[@]}"} \ + "${qt_configure_args[@]}" \ + -- \ + -DCMAKE_OSX_DEPLOYMENT_TARGET="${target}" \ + ${qt_cmake_args[@]+"${qt_cmake_args[@]}"} + ) + cmake --build "${qt_build}" -j "${jobs}" + cmake --install "${qt_build}" + else + run_cmake_build "${qt_source}" "${qt_build}" \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX="${prefix}" \ + -DCMAKE_OSX_DEPLOYMENT_TARGET="${target}" \ + -DQT_BUILD_EXAMPLES=OFF \ + -DQT_BUILD_TESTS=OFF \ + -DQT_FEATURE_dbus=OFF \ + -DQT_FEATURE_openssl=OFF \ + -DQT_FEATURE_glib=OFF \ + -DQT_FEATURE_icu=OFF \ + -DQT_FEATURE_cups=OFF \ + -DQT_FEATURE_fontconfig=OFF \ + -DQT_FEATURE_gtk=OFF \ + -DQT_FEATURE_opengl=OFF \ + -DQT_FEATURE_opengles2=OFF \ + ${qt_cmake_args[@]+"${qt_cmake_args[@]}"} + fi +fi + +"${script_dir}/macos-check-deployment-target.sh" "${prefix}" "${target}" + +env_file="${prefix}/winuae-macos-deps-env.sh" +cat > "${env_file}" </../winuae-macos-deps. + +Environment: + WINUAE_MACOS_DEPLOYMENT_TARGET Minimum macOS version. Defaults to 13.0. + WINUAE_QEMU_DEPS_BUILD_DIR Build directory. Defaults to + /build/qemu-deps. + WINUAE_DEPS_JOBS Parallel build jobs. Defaults to hw.ncpu. + WINUAE_GLIB_SOURCE GLib source tree. Required. + WINUAE_MESON meson executable. Defaults to meson in PATH + or ../qemu-uae-v11.0/build/pyvenv/bin/meson. + WINUAE_NINJA ninja executable. Defaults to ninja in PATH. + WINUAE_QEMU_BUILD_TOOLS_DIR Optional tools prefix. If set, + /bin/ninja is used as fallback. + WINUAE_GLIB_MESON_ARGS Extra arguments passed to GLib Meson. + +Extra argument variables are whitespace-separated argv fragments. +EOF +} + +if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then + usage + exit 0 +fi + +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source_dir="$(cd "${script_dir}/.." && pwd)" +target="${WINUAE_MACOS_DEPLOYMENT_TARGET:-13.0}" +prefix="${1:-${WINUAE_QEMU_DEPS_PREFIX:-${WINUAE_DEPS_PREFIX:-${source_dir}/../winuae-macos-deps}}}" +build_dir="${WINUAE_QEMU_DEPS_BUILD_DIR:-${prefix}/build/qemu-deps}" +glib_source="${WINUAE_GLIB_SOURCE:-}" + +if [[ "$(uname -s)" != "Darwin" ]]; then + echo "error: macOS QEMU dependency builds require Darwin/macOS" >&2 + exit 1 +fi + +jobs="${WINUAE_DEPS_JOBS:-}" +if [[ -z "${jobs}" ]]; then + jobs="$(sysctl -n hw.ncpu 2>/dev/null || echo 8)" +fi + +require_source() { + local name="$1" + local path="$2" + if [[ -z "${path}" ]]; then + echo "error: ${name} source path is required" >&2 + usage >&2 + exit 1 + fi + if [[ ! -d "${path}" ]]; then + echo "error: ${name} source directory not found: ${path}" >&2 + exit 1 + fi +} + +find_tool() { + local env_value="$1" + local tool_name="$2" + local fallback="$3" + + if [[ -n "${env_value}" ]]; then + echo "${env_value}" + return + fi + if command -v "${tool_name}" >/dev/null 2>&1; then + command -v "${tool_name}" + return + fi + if [[ -n "${fallback}" && -x "${fallback}" ]]; then + echo "${fallback}" + return + fi + + echo "error: ${tool_name} not found" >&2 + exit 1 +} + +split_extra_args() { + extra_args=() + if [[ -n "${1:-}" ]]; then + # Extra-arg variables are whitespace-separated argv fragments. + # Split once here and pass the result as an array at call sites. + # shellcheck disable=SC2206 + extra_args=($1) + fi +} + +run_meson_build() { + local src="$1" + local bld="$2" + shift 2 + + if [[ -f "${bld}/build.ninja" ]]; then + "${meson_executable}" setup --reconfigure "${bld}" "$@" + else + "${meson_executable}" setup "${bld}" "${src}" "$@" + fi + "${ninja_executable}" -C "${bld}" -j "${jobs}" + "${ninja_executable}" -C "${bld}" install +} + +require_source "GLib" "${glib_source}" + +meson_fallback="${source_dir}/../qemu-uae-v11.0/build/pyvenv/bin/meson" +ninja_fallback="" +if [[ -n "${WINUAE_QEMU_BUILD_TOOLS_DIR:-}" ]]; then + ninja_fallback="${WINUAE_QEMU_BUILD_TOOLS_DIR}/bin/ninja" +fi +meson_executable="$(find_tool "${WINUAE_MESON:-}" meson "${meson_fallback}")" +ninja_executable="$(find_tool "${WINUAE_NINJA:-}" ninja "${ninja_fallback}")" + +mkdir -p "${prefix}" "${build_dir}" + +export MACOSX_DEPLOYMENT_TARGET="${target}" +export PATH="$(dirname "${ninja_executable}"):${prefix}/bin:${PATH}" +export PKG_CONFIG_LIBDIR="${prefix}/lib/pkgconfig:${prefix}/share/pkgconfig" + +common_meson_args=( + --prefix="${prefix}" + --libdir=lib + --buildtype=release + -Ddefault_library=shared +) + +glib_args=( + "${common_meson_args[@]}" + --force-fallback-for=libpcre2-8,libffi,intl + -Dtests=false + -Dinstalled_tests=false + -Dglib_debug=disabled + -Dglib_assert=false + -Dglib_checks=false + -Dman-pages=disabled + -Ddocumentation=false + -Dgtk_doc=false + -Dnls=disabled + -Dselinux=disabled + -Dxattr=false + -Dlibmount=disabled + -Dsysprof=disabled + -Dintrospection=disabled + -Ddtrace=disabled + -Dsystemtap=disabled +) +if [[ -n "${WINUAE_GLIB_MESON_ARGS:-}" ]]; then + split_extra_args "${WINUAE_GLIB_MESON_ARGS}" + glib_args+=(${extra_args[@]+"${extra_args[@]}"}) +fi + +run_meson_build "${glib_source}" "${build_dir}/glib" "${glib_args[@]}" + +"${script_dir}/macos-check-deployment-target.sh" "${prefix}" "${target}" + +env_file="${prefix}/winuae-macos-deps-env.sh" +cat > "${env_file}" </package. + +Environment: + WINUAE_SKIP_MACDEPLOYQT=1 Do not run macdeployqt even if it is available. + WINUAE_SKIP_MACOS_DEPLOYMENT_CHECK=1 + Do not check bundled Mach-O deployment targets. + WINUAE_SKIP_CODESIGN=1 Do not ad-hoc codesign the bundle. + WINUAE_CODESIGN_IDENTITY codesign identity. Defaults to "-" for ad-hoc. + WINUAE_CODESIGN_OPTIONS Extra options passed to codesign, for example + "--options runtime --timestamp". + WINUAE_CODESIGN_ENTITLEMENTS + Optional entitlements plist passed to codesign. + WINUAE_QEMU_UAE_PLUGIN Optional qemu-uae.so path to copy into + Contents/PlugIns. +EOF +} + +if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then + usage + exit 0 +fi + +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source_dir="$(cd "${script_dir}/.." && pwd)" +build_dir="${1:-${WINUAE_BUILD_DIR:-$(pwd)}}" +output_dir="${2:-${build_dir}/package}" +executable="${build_dir}/winuae_unix" +app_dir="${output_dir}/WinUAE.app" +contents_dir="${app_dir}/Contents" +macos_dir="${contents_dir}/MacOS" +resources_dir="${contents_dir}/Resources" + +if [[ "$(uname -s)" != "Darwin" ]]; then + echo "error: macOS app bundling requires Darwin/macOS" >&2 + exit 1 +fi + +if [[ ! -x "${executable}" ]]; then + echo "error: executable not found: ${executable}" >&2 + echo "hint: build winuae_unix first, or pass the CMake build directory" >&2 + exit 1 +fi + +major="$(awk '/^#define UAEMAJOR / { print $3; exit }' "${source_dir}/include/options.h")" +minor="$(awk '/^#define UAEMINOR / { print $3; exit }' "${source_dir}/include/options.h")" +revision="$(awk '/^#define UAESUBREV / { print $3; exit }' "${source_dir}/include/options.h")" +version="${major:-0}.${minor:-0}.${revision:-0}" +deployment_target="${WINUAE_MACOS_DEPLOYMENT_TARGET:-}" +if [[ -z "${deployment_target}" && -f "${build_dir}/CMakeCache.txt" ]]; then + deployment_target="$(awk -F= '/^CMAKE_OSX_DEPLOYMENT_TARGET:/ { print $2; exit }' "${build_dir}/CMakeCache.txt")" +fi +if [[ -z "${deployment_target}" ]]; then + deployment_target="13.0" +fi + +cmake_cache_value() { + local key="$1" + if [[ -f "${build_dir}/CMakeCache.txt" ]]; then + awk -F= -v key="${key}" '$1 ~ "^" key ":" { print $2; exit }' "${build_dir}/CMakeCache.txt" + fi +} + +append_qt_plugin_candidate() { + local candidate="$1" + if [[ -n "${candidate}" && -f "${candidate}/platforms/libqcocoa.dylib" ]]; then + qt_plugin_candidates+=("${candidate}") + fi +} + +split_extra_args() { + if [[ -n "${1:-}" ]]; then + # Intentionally split user-provided extra flags the same way a shell would. + # shellcheck disable=SC2206 + extra_args=($1) + else + extra_args=() + fi +} + +path_in_list() { + local needle="$1" + shift + local item + for item in "$@"; do + if [[ "${item}" == "${needle}" ]]; then + return 0 + fi + done + return 1 +} + +copy_private_dylib_deps() { + local root_binary="$1" + local install_prefix="$2" + local frameworks_dir="${contents_dir}/Frameworks" + local queue=("${root_binary}") + local visited=() + + mkdir -p "${frameworks_dir}" + while [[ ${#queue[@]} -gt 0 ]]; do + local binary="${queue[0]}" + queue=("${queue[@]:1}") + if path_in_list "${binary}" ${visited[@]+"${visited[@]}"}; then + continue + fi + visited+=("${binary}") + + local dep + while IFS= read -r dep; do + case "${dep}" in + ""|@*|/usr/lib/*|/System/Library/*) + continue + ;; + esac + if [[ ! -f "${dep}" ]]; then + continue + fi + + local name target + name="$(basename "${dep}")" + target="${frameworks_dir}/${name}" + if [[ ! -f "${target}" ]]; then + cp "${dep}" "${target}" + chmod u+w "${target}" 2>/dev/null || true + install_name_tool -id "@rpath/${name}" "${target}" \ + 2>/dev/null || true + fi + install_name_tool -change "${dep}" "${install_prefix}/${name}" \ + "${binary}" 2>/dev/null || true + if ! path_in_list "${target}" ${visited[@]+"${visited[@]}"} \ + && ! path_in_list "${target}" ${queue[@]+"${queue[@]}"}; then + queue+=("${target}") + fi + done < <(otool -L "${binary}" | awk 'NR > 1 { print $1 }') + done +} + +rm -rf "${app_dir}" +mkdir -p "${macos_dir}" "${resources_dir}/od-win32/resources" + +cp "${executable}" "${macos_dir}/WinUAE" +find "${source_dir}/od-win32/resources" -maxdepth 1 -type f \ + ! -name '*.rc' \ + ! -name '*.manifest' \ + ! -name 'resource.h' \ + -exec cp '{}' "${resources_dir}/od-win32/resources/" ';' +cp "${source_dir}/README_unix.md" "${resources_dir}/README_unix.md" + +if [[ -f "${source_dir}/od-win32/resources/winuae.ico" ]]; then + cp "${source_dir}/od-win32/resources/winuae.ico" "${resources_dir}/winuae.ico" + if command -v sips >/dev/null 2>&1; then + sips -s format icns "${source_dir}/od-win32/resources/winuae.ico" --out "${resources_dir}/WinUAE.icns" >/dev/null + fi +fi + +cat > "${contents_dir}/Info.plist" < + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + WinUAE + CFBundleExecutable + WinUAE + CFBundleIdentifier + net.winuae.unix + CFBundleIconFile + WinUAE.icns + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + WinUAE + CFBundlePackageType + APPL + CFBundleShortVersionString + ${version} + CFBundleVersion + ${version} + LSMinimumSystemVersion + ${deployment_target} + NSHighResolutionCapable + + CFBundleDocumentTypes + + + CFBundleTypeExtensions + + uae + + CFBundleTypeName + WinUAE Configuration + CFBundleTypeRole + Editor + + + + +EOF + +qemu_uae_plugin="" +for candidate in \ + "${WINUAE_QEMU_UAE_PLUGIN:-}" \ + "${build_dir}/qemu-uae.so" \ + "${build_dir}/plugins/qemu-uae.so" \ + "${source_dir}/../qemu-uae-v11.0/build/qemu-uae.so" +do + if [[ -n "${candidate}" && -f "${candidate}" ]]; then + qemu_uae_plugin="${candidate}" + break + fi +done + +copy_qemu_uae_plugin() { + if [[ -n "${qemu_uae_plugin}" ]]; then + mkdir -p "${contents_dir}/PlugIns" + cp "${qemu_uae_plugin}" "${contents_dir}/PlugIns/qemu-uae.so" + install_name_tool -add_rpath "@loader_path/../Frameworks" \ + "${contents_dir}/PlugIns/qemu-uae.so" 2>/dev/null || true + copy_private_dylib_deps \ + "${contents_dir}/PlugIns/qemu-uae.so" \ + "@loader_path/../Frameworks" + fi +} + +macdeployqt_executable="${WINUAE_MACDEPLOYQT:-}" +if [[ -z "${macdeployqt_executable}" ]]; then + macdeployqt_executable="$(cmake_cache_value MACDEPLOYQT_EXECUTABLE)" +fi +if [[ -z "${macdeployqt_executable}" ]]; then + macdeployqt_executable="$(command -v macdeployqt || true)" +fi + +if [[ "${WINUAE_SKIP_MACDEPLOYQT:-0}" != "1" && -n "${macdeployqt_executable}" && -x "${macdeployqt_executable}" ]]; then + macdeployqt_args=("${app_dir}" -always-overwrite -no-plugins -verbose=0) + if "${macdeployqt_executable}" -help 2>&1 | grep -q -- "-no-codesign"; then + macdeployqt_args+=(-no-codesign) + fi + "${macdeployqt_executable}" "${macdeployqt_args[@]}" + + qt_plugin_root="" + qt_plugin_candidates=() + append_qt_plugin_candidate "${WINUAE_QT_PLUGIN_ROOT:-}" + + qt6_dir="$(cmake_cache_value Qt6_DIR)" + if [[ -n "${qt6_dir}" && -d "${qt6_dir}" ]]; then + qt_prefix="$(cd "${qt6_dir}/../../.." && pwd)" + append_qt_plugin_candidate "${qt_prefix}/plugins" + append_qt_plugin_candidate "${qt_prefix}/share/qt/plugins" + append_qt_plugin_candidate "${qt_prefix}/share/qt6/plugins" + if [[ -x "${qt_prefix}/bin/qtpaths" ]]; then + append_qt_plugin_candidate "$("${qt_prefix}/bin/qtpaths" --plugin-dir 2>/dev/null || true)" + fi + fi + + macdeployqt_dir="$(cd "$(dirname "${macdeployqt_executable}")" && pwd)" + if [[ -x "${macdeployqt_dir}/qtpaths" ]]; then + append_qt_plugin_candidate "$("${macdeployqt_dir}/qtpaths" --plugin-dir 2>/dev/null || true)" + fi + + for candidate in "${qt_plugin_candidates[@]}" \ + /opt/homebrew/share/qt/plugins \ + /opt/homebrew/opt/qt/share/qt/plugins \ + /opt/homebrew/opt/qt6/share/qt/plugins \ + /opt/homebrew/opt/qt@6/share/qt/plugins \ + /usr/local/share/qt/plugins \ + /usr/local/opt/qt/share/qt/plugins \ + /usr/local/opt/qt6/share/qt/plugins \ + /usr/local/opt/qt@6/share/qt/plugins + do + if [[ -n "${candidate}" && -f "${candidate}/platforms/libqcocoa.dylib" ]]; then + qt_plugin_root="${candidate}" + break + fi + done + + if [[ -n "${qt_plugin_root}" ]]; then + copy_qt_plugin() { + local relative="$1" + local source="${qt_plugin_root}/${relative}" + local target="${contents_dir}/PlugIns/${relative}" + if [[ -f "${source}" ]]; then + mkdir -p "$(dirname "${target}")" + cp "${source}" "${target}" + install_name_tool -add_rpath "@loader_path/../../Frameworks" "${target}" 2>/dev/null || true + fi + } + copy_qt_plugin "platforms/libqcocoa.dylib" + copy_qt_plugin "imageformats/libqico.dylib" + copy_qt_plugin "styles/libqmacstyle.dylib" + fi +fi + +copy_qemu_uae_plugin + +if [[ "${WINUAE_SKIP_MACOS_DEPLOYMENT_CHECK:-0}" != "1" ]]; then + "${script_dir}/macos-check-deployment-target.sh" "${app_dir}" "${deployment_target}" >&2 +fi + +if [[ "${WINUAE_SKIP_CODESIGN:-0}" != "1" ]] && command -v codesign >/dev/null 2>&1; then + codesign_identity="${WINUAE_CODESIGN_IDENTITY:--}" + codesign_args=(--force --deep --sign "${codesign_identity}") + split_extra_args "${WINUAE_CODESIGN_OPTIONS:-}" + codesign_args+=(${extra_args[@]+"${extra_args[@]}"}) + if [[ -n "${WINUAE_CODESIGN_ENTITLEMENTS:-}" ]]; then + codesign_args+=(--entitlements "${WINUAE_CODESIGN_ENTITLEMENTS}") + fi + codesign "${codesign_args[@]}" "${app_dir}" +fi + +echo "${app_dir}" diff --git a/tools/macos-check-deployment-target.sh b/tools/macos-check-deployment-target.sh new file mode 100755 index 00000000..560bbae2 --- /dev/null +++ b/tools/macos-check-deployment-target.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat <&2 + exit 1 +fi +if [[ -z "${root}" || -z "${target}" ]]; then + usage >&2 + exit 1 +fi +if [[ ! -e "${root}" ]]; then + echo "error: path not found: ${root}" >&2 + exit 1 +fi + +version_gt() { + local a="$1" + local b="$2" + local ai bi + IFS=. read -r -a av <<< "${a}" + IFS=. read -r -a bv <<< "${b}" + for i in 0 1 2; do + ai="${av[$i]:-0}" + bi="${bv[$i]:-0}" + if ((10#${ai} > 10#${bi})); then + return 0 + fi + if ((10#${ai} < 10#${bi})); then + return 1 + fi + done + return 1 +} + +mach_o_minos() { + otool -l "$1" 2>/dev/null | awk ' + /LC_BUILD_VERSION/ { build = 1; old = 0; next } + build && /minos/ { print $2; exit } + /LC_VERSION_MIN_MACOSX/ { old = 1; build = 0; next } + old && /version/ { print $2; exit } + ' +} + +check_file() { + local file="$1" + local info minos + + info="$(file -b "${file}" 2>/dev/null || true)" + case "${info}" in + *Mach-O*) ;; + *) return 0 ;; + esac + + minos="$(mach_o_minos "${file}")" + if [[ -n "${minos}" ]] && version_gt "${minos}" "${target}"; then + echo "error: ${file} requires macOS ${minos}, newer than deployment target ${target}" >&2 + return 1 + fi + return 0 +} + +failed=0 +if [[ -f "${root}" ]]; then + check_file "${root}" || failed=1 +else + while IFS= read -r -d '' file_path; do + check_file "${file_path}" || failed=1 + done < <(find "${root}" -type f -print0) +fi + +if ((failed)); then + exit 1 +fi +echo "verified macOS deployment target ${target}: ${root}" diff --git a/tools/macos-dmg.sh b/tools/macos-dmg.sh new file mode 100755 index 00000000..b811a4a1 --- /dev/null +++ b/tools/macos-dmg.sh @@ -0,0 +1,231 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat </package. + +Environment: + WINUAE_DMG_CODESIGN_IDENTITY codesign identity for the final DMG. + Defaults to WINUAE_CODESIGN_IDENTITY when set. + WINUAE_DMG_CODESIGN_OPTIONS Extra options passed to codesign for the DMG. + WINUAE_NOTARY_PROFILE notarytool keychain profile. When set, submit + the final DMG and staple the ticket. + WINUAE_SKIP_NOTARIZATION=1 Do not submit/staple even if a profile is set. +EOF +} + +if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then + usage + exit 0 +fi + +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source_dir="$(cd "${script_dir}/.." && pwd)" +build_dir="${1:-${WINUAE_BUILD_DIR:-$(pwd)}}" +output_dir="${2:-${build_dir}/package}" + +if [[ "$(uname -s)" != "Darwin" ]]; then + echo "error: macOS DMG creation requires Darwin/macOS" >&2 + exit 1 +fi + +major="$(awk '/^#define UAEMAJOR / { print $3; exit }' "${source_dir}/include/options.h")" +minor="$(awk '/^#define UAEMINOR / { print $3; exit }' "${source_dir}/include/options.h")" +revision="$(awk '/^#define UAESUBREV / { print $3; exit }' "${source_dir}/include/options.h")" +version="${major:-0}.${minor:-0}.${revision:-0}" + +app_dir="$("${script_dir}/macos-bundle.sh" "${build_dir}" "${output_dir}" | awk 'NF { line = $0 } END { print line }')" +staging_dir="${output_dir}/dmg-root" +volume_name="WinUAE" +rw_dmg="${output_dir}/WinUAE-${version}.rw.dmg" +final_dmg="${output_dir}/WinUAE-${version}.dmg" +mount_dir="" + +cleanup() { + if [[ -n "${mount_dir}" && -d "${mount_dir}" ]]; then + hdiutil detach "${mount_dir}" -quiet >/dev/null 2>&1 || true + rmdir "${mount_dir}" >/dev/null 2>&1 || true + fi +} +trap cleanup EXIT + +split_extra_args() { + if [[ -n "${1:-}" ]]; then + # Intentionally split user-provided extra flags the same way a shell would. + # shellcheck disable=SC2206 + extra_args=($1) + else + extra_args=() + fi +} + +rm -rf "${staging_dir}" "${rw_dmg}" "${final_dmg}" +mkdir -p "${staging_dir}/.background" +cp -R "${app_dir}" "${staging_dir}/WinUAE.app" +ln -s /Applications "${staging_dir}/Applications" + +volume_icon="${app_dir}/Contents/Resources/WinUAE.icns" +apply_volume_icon() { + local target_dir="$1" + + if [[ ! -f "${volume_icon}" ]]; then + return + fi + + cp "${volume_icon}" "${target_dir}/.VolumeIcon.icns" + if command -v SetFile >/dev/null 2>&1; then + SetFile -a C "${target_dir}" || true + SetFile -a V "${target_dir}/.VolumeIcon.icns" || true + fi +} + +apply_volume_icon "${staging_dir}" + +background_tiff="${staging_dir}/.background/background.tiff" +background_source="${source_dir}/od-unix/graphics/dmg_background.tiff" +if [[ ! -f "${background_source}" ]]; then + echo "error: missing DMG background: ${background_source}" >&2 + exit 1 +fi +cp "${background_source}" "${background_tiff}" + +hdiutil create -volname "${volume_name}" -srcfolder "${staging_dir}" -fs HFS+ -format UDRW -ov "${rw_dmg}" >/dev/null +mount_dir="$(hdiutil attach "${rw_dmg}" -readwrite -noverify -noautoopen | awk -F '\t' '/\/Volumes\// { print $NF; exit }')" +if [[ -z "${mount_dir}" || ! -d "${mount_dir}" ]]; then + echo "error: failed to mount ${rw_dmg}" >&2 + exit 1 +fi + +apply_volume_icon "${mount_dir}" + +require_finder_layout_records() { + local ds_store="$1" + local missing=0 + + for record in Iloc bwsp icvp; do + if ! LC_ALL=C grep -aq "${record}" "${ds_store}"; then + echo "error: Finder layout metadata is missing ${record} record in ${ds_store}" >&2 + missing=1 + fi + done + + return "${missing}" +} + +if ! command -v osascript >/dev/null 2>&1; then + echo "error: osascript is required to write the DMG Finder layout" >&2 + exit 1 +fi + +osascript </dev/null 2>&1; then + break + fi + sleep 0.5 +done +if [[ ! -f "${mount_dir}/.DS_Store" ]]; then + echo "error: Finder did not write ${mount_dir}/.DS_Store; DMG background layout was not saved" >&2 + exit 1 +fi +require_finder_layout_records "${mount_dir}/.DS_Store" + +apply_volume_icon "${mount_dir}" +if [[ -f "${volume_icon}" ]] && command -v SetFile >/dev/null 2>&1 && command -v GetFileInfo >/dev/null 2>&1; then + volume_attrs="$(GetFileInfo -a "${mount_dir}" 2>/dev/null || true)" + case "${volume_attrs}" in + *C*) ;; + *) + echo "error: custom volume icon attribute was not set on ${mount_dir}" >&2 + exit 1 + ;; + esac +fi + +sync +hdiutil detach "${mount_dir}" -quiet +mount_dir="" +hdiutil convert "${rw_dmg}" -format UDZO -imagekey zlib-level=9 -o "${final_dmg}" -ov >/dev/null + +dmg_codesign_identity="${WINUAE_DMG_CODESIGN_IDENTITY:-${WINUAE_CODESIGN_IDENTITY:-}}" +if [[ -n "${dmg_codesign_identity}" && "${dmg_codesign_identity}" != "-" ]] && command -v codesign >/dev/null 2>&1; then + dmg_codesign_args=(--force --sign "${dmg_codesign_identity}") + split_extra_args "${WINUAE_DMG_CODESIGN_OPTIONS:-}" + dmg_codesign_args+=(${extra_args[@]+"${extra_args[@]}"}) + codesign "${dmg_codesign_args[@]}" "${final_dmg}" +fi + +hdiutil verify "${final_dmg}" >/dev/null + +if [[ "${WINUAE_SKIP_NOTARIZATION:-0}" != "1" && -n "${WINUAE_NOTARY_PROFILE:-}" ]]; then + if ! command -v xcrun >/dev/null 2>&1; then + echo "error: notarization requires xcrun/notarytool" >&2 + exit 1 + fi + xcrun notarytool submit "${final_dmg}" --keychain-profile "${WINUAE_NOTARY_PROFILE}" --wait + xcrun stapler staple "${final_dmg}" +fi + +"${script_dir}/macos-verify-dmg.sh" "${final_dmg}" >/dev/null +rm -rf "${rw_dmg}" "${staging_dir}" + +echo "${final_dmg}" diff --git a/tools/macos-smoke-app.sh b/tools/macos-smoke-app.sh new file mode 100755 index 00000000..dd945952 --- /dev/null +++ b/tools/macos-smoke-app.sh @@ -0,0 +1,123 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat </dev/null 2>&1 || true +on run argv + tell application id (item 1 of argv) to quit +end run +APPLESCRIPT + fi + if [[ -n "${smoke_home}" && -d "${smoke_home}" ]]; then + rm -rf "${smoke_home}" + fi + if [[ -n "${smoke_log}" && -f "${smoke_log}" ]]; then + rm -f "${smoke_log}" + fi + if [[ -n "${timeout_file}" && -f "${timeout_file}" ]]; then + rm -f "${timeout_file}" + fi +} +trap cleanup EXIT + +if [[ "$(uname -s)" != "Darwin" ]]; then + echo "error: macOS app smoke testing requires Darwin/macOS" >&2 + exit 1 +fi + +if [[ -z "${app_path}" ]]; then + usage >&2 + exit 1 +fi + +if [[ -d "${app_path}/WinUAE.app" ]]; then + app_path="${app_path}/WinUAE.app" +fi + +executable="${app_path}/Contents/MacOS/WinUAE" +if [[ ! -x "${executable}" ]]; then + echo "error: app executable not found: ${executable}" >&2 + exit 1 +fi + +bundle_id="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleIdentifier' "${app_path}/Contents/Info.plist" 2>/dev/null || true)" +if [[ -z "${bundle_id}" ]]; then + echo "error: CFBundleIdentifier missing from ${app_path}/Contents/Info.plist" >&2 + exit 1 +fi + +timeout="${WINUAE_MACOS_SMOKE_TIMEOUT:-20}" +smoke_home="$(mktemp -d -t winuae-app-smoke-home.XXXXXX)" +smoke_log="$(mktemp -t winuae-app-smoke-log.XXXXXX)" +timeout_file="$(mktemp -t winuae-app-smoke-timeout.XXXXXX)" +rm -f "${timeout_file}" + +open -n -F -W \ + --env "HOME=${smoke_home}" \ + --env "WINUAE_MACOS_APP_SMOKE=1" \ + -o "${smoke_log}" \ + --stderr "${smoke_log}" \ + "${app_path}" & +open_pid="$!" +launched=1 + +( + sleep "${timeout}" + if kill -0 "${open_pid}" >/dev/null 2>&1; then + : > "${timeout_file}" + osascript - "${bundle_id}" <<'APPLESCRIPT' >/dev/null 2>&1 || true +on run argv + tell application id (item 1 of argv) to quit +end run +APPLESCRIPT + fi +) & +watchdog_pid="$!" + +open_status=0 +wait "${open_pid}" || open_status="$?" +kill "${watchdog_pid}" >/dev/null 2>&1 || true +wait "${watchdog_pid}" >/dev/null 2>&1 || true + +if [[ -f "${timeout_file}" ]]; then + echo "error: timed out waiting for packaged Qt app smoke mode to finish" >&2 + sed -n '1,120p' "${smoke_log}" >&2 + exit 1 +fi +if [[ "${open_status}" != "0" ]]; then + echo "error: packaged app launch failed with status ${open_status}" >&2 + sed -n '1,120p' "${smoke_log}" >&2 + exit 1 +fi +if ! grep -q '^WINUAE_QT_SMOKE_WINDOW_VISIBLE$' "${smoke_log}"; then + echo "error: packaged app did not report a visible Qt configuration window" >&2 + sed -n '1,120p' "${smoke_log}" >&2 + exit 1 +fi + +echo "verified packaged Qt app launch: ${app_path}" diff --git a/tools/macos-verify-dmg.sh b/tools/macos-verify-dmg.sh new file mode 100755 index 00000000..575e5c0f --- /dev/null +++ b/tools/macos-verify-dmg.sh @@ -0,0 +1,148 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat </dev/null 2>&1 || true + fi +} +trap cleanup EXIT + +if [[ "$(uname -s)" != "Darwin" ]]; then + echo "error: macOS DMG verification requires Darwin/macOS" >&2 + exit 1 +fi + +if [[ -z "${dmg_path}" ]]; then + usage >&2 + exit 1 +fi + +if [[ ! -f "${dmg_path}" ]]; then + echo "error: DMG not found: ${dmg_path}" >&2 + exit 1 +fi + +hdiutil verify "${dmg_path}" >/dev/null +mount_dir="$(hdiutil attach "${dmg_path}" -readonly -noverify -noautoopen | awk -F '\t' '/\/Volumes\// { print $NF; exit }')" +if [[ -z "${mount_dir}" || ! -d "${mount_dir}" ]]; then + echo "error: failed to mount ${dmg_path}" >&2 + exit 1 +fi + +app_dir="${mount_dir}/WinUAE.app" +info_plist="${app_dir}/Contents/Info.plist" + +require_path() { + local path="$1" + local description="$2" + if [[ ! -e "${path}" ]]; then + echo "error: missing ${description}: ${path}" >&2 + exit 1 + fi +} + +require_file() { + local path="$1" + local description="$2" + if [[ ! -f "${path}" ]]; then + echo "error: missing ${description}: ${path}" >&2 + exit 1 + fi +} + +require_path "${app_dir}" "app bundle" +require_file "${info_plist}" "Info.plist" +require_file "${app_dir}/Contents/MacOS/WinUAE" "bundle executable" +if [[ ! -x "${app_dir}/Contents/MacOS/WinUAE" ]]; then + echo "error: bundle executable is not executable: ${app_dir}/Contents/MacOS/WinUAE" >&2 + exit 1 +fi +require_file "${app_dir}/Contents/Resources/WinUAE.icns" "application icon" +require_file "${app_dir}/Contents/Resources/README_unix.md" "bundled README" + +if [[ ! -L "${mount_dir}/Applications" ]]; then + echo "error: missing /Applications symlink" >&2 + exit 1 +fi +if [[ "$(readlink "${mount_dir}/Applications")" != "/Applications" ]]; then + echo "error: Applications symlink does not point to /Applications" >&2 + exit 1 +fi + +require_file "${mount_dir}/.DS_Store" "Finder layout metadata" +require_file "${mount_dir}/.background/background.tiff" "Finder background image" +require_file "${mount_dir}/.VolumeIcon.icns" "volume icon" + +for record in Iloc bwsp icvp; do + if ! LC_ALL=C grep -aq "${record}" "${mount_dir}/.DS_Store"; then + echo "error: Finder layout metadata is missing ${record} record in ${mount_dir}/.DS_Store" >&2 + exit 1 + fi +done + +if command -v GetFileInfo >/dev/null 2>&1; then + volume_attrs="$(GetFileInfo -a "${mount_dir}" 2>/dev/null || true)" + case "${volume_attrs}" in + *C*) ;; + *) + echo "error: custom volume icon attribute is not set on ${mount_dir}" >&2 + exit 1 + ;; + esac +fi + +plist_get() { + /usr/libexec/PlistBuddy -c "Print $1" "${info_plist}" 2>/dev/null || true +} + +if [[ "$(plist_get ':CFBundleExecutable')" != "WinUAE" ]]; then + echo "error: CFBundleExecutable is not WinUAE" >&2 + exit 1 +fi +if [[ "$(plist_get ':CFBundleIconFile')" != "WinUAE.icns" ]]; then + echo "error: CFBundleIconFile is not WinUAE.icns" >&2 + exit 1 +fi +if [[ "$(plist_get ':CFBundleDocumentTypes:0:CFBundleTypeExtensions:0')" != "uae" ]]; then + echo "error: .uae document type is not registered in Info.plist" >&2 + exit 1 +fi + +launch_home="$(mktemp -d -t winuae-dmg-home.XXXXXX)" +launch_log="$(mktemp -t winuae-dmg-launch.XXXXXX)" +if ! HOME="${launch_home}" QT_QPA_PLATFORM=offscreen SDL_VIDEODRIVER=dummy "${app_dir}/Contents/MacOS/WinUAE" -h >"${launch_log}" 2>&1; then + echo "error: bundled executable did not start successfully from the mounted DMG" >&2 + sed -n '1,120p' "${launch_log}" >&2 + exit 1 +fi + +echo "verified ${dmg_path}" -- 2.47.3