From 2eceae4fdca02d1580c9d830dc7a6e066d7e45f8 Mon Sep 17 00:00:00 2001 From: esi <41133734+vapidinfinity@users.noreply.github.com> Date: Tue, 23 Dec 2025 15:43:43 +0100 Subject: [PATCH 01/15] feat!(build): bundle necessary dylibs --- .github/workflows/build.yml | 8 +- .github/workflows/dylib_bundler.zsh | 211 ++++++++++++++++++++++++++++ 2 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/dylib_bundler.zsh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4758a7ce2c3d..a65d259eb110 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -57,7 +57,8 @@ jobs: sudo mkdir -p /Library/Developer/CommandLineTools/SDKs curl -fL https://github.com/Gcenx/macos-sdk/releases/download/12.3/MacOSX12.3.tar.bz2 \ | sudo tar -xj -C /Library/Developer/CommandLineTools/SDKs - + + # ensure that when updating dependencies, the dylib bundler script is also updated - name: install build & runtime dependencies run: | brew install bison \ @@ -158,6 +159,11 @@ jobs: # copy gptk libraries ditto src/external/gptk-*/redist/lib/ Engine/wine/lib/ + + - name: bundle dylib dependencies + run: | + chmod +x src/.github/dylib_bundler.zsh + ENGINE_DIR=Engine/wine src/.github/dylib_bundler.zsh - name: copy engine properties file run: cp -R src/Mythic/Properties.plist Engine/ diff --git a/.github/workflows/dylib_bundler.zsh b/.github/workflows/dylib_bundler.zsh new file mode 100644 index 000000000000..4f2d1bb9ab66 --- /dev/null +++ b/.github/workflows/dylib_bundler.zsh @@ -0,0 +1,211 @@ +#!/bin/zsh + +# Bundle dylib dependencies for Wine distribution +# This script finds all dylib dependencies, copies them, and fixes install names + +set -e + +# Output directory (can be overridden via environment variable) +ENGINE_DIR="${ENGINE_DIR:-Engine/wine}" + +# GStreamer plugins to bundle +GSTREAMER_LIBS=( + "libgstapplemedia" + "libgstasf" + "libgstaudioconvert" + "libgstaudioparsers" + "libgstaudioresample" + "libgstavi" + "libgstcoreelements" + "libgstdebug" + "libgstdeinterlace" + "libgstid3demux" + "libgstisomp4" + "libgstlibav" + "libgstopengl" + "libgstplayback" + "libgsttypefindfunctions" + "libgstvideoconvertscale" + "libgstvideofilter" + "libgstvideoparsersbad" + "libgstwavparse" +) + +# Non-GStreamer libraries to bundle +LIBS=( + "libMoltenVK" + "libSDL2-2.0.0" + "libpcap" + "libfreetype" + "libgnutls" + "libpng16" + "libjpeg" + "libtiff" +) + +# Global array to store all discovered dylibs (unique entries) +typeset -aU all_dylibs +# Queue for iterative processing +typeset -a queue + +# Resolve @rpath dependencies by searching in Homebrew's lib directory +resolve_rpath() { + local ref_dylib="$1" + local dylib_name="${ref_dylib#@rpath/}" + local brew_lib_dir="$(brew --prefix)/lib" + local resolved_path="${brew_lib_dir}/${dylib_name}" + + if [[ -f "$resolved_path" ]]; then + echo "$resolved_path" + else + echo "" + fi +} + +# Find all dylib dependencies iteratively +find_dylib_dependencies() { + local dylib="$1" + queue+=("$dylib") + + while [[ ${#queue[@]} -gt 0 ]]; do + local current_dylib="${queue[1]}" + queue=("${queue[@]:1}") + + local referenced_dylibs=($(otool -L "$current_dylib" 2>/dev/null | awk '/^\t/ {print $1}' | grep '\.dylib')) + + for ref_dylib in $referenced_dylibs; do + # Skip system libraries + if [[ "$ref_dylib" == /usr/lib/* ]] || [[ "$ref_dylib" == /System/* ]]; then + continue + fi + + # Resolve @rpath references + if [[ "$ref_dylib" == @rpath/* ]]; then + ref_dylib=$(resolve_rpath "$ref_dylib") + if [[ -z "$ref_dylib" ]]; then + continue + fi + fi + + # Skip relative path references + if [[ "$ref_dylib" == @loader_path/* ]] || [[ "$ref_dylib" == @executable_path/* ]]; then + continue + fi + + # Add to array and queue if not already present + if [[ ! " ${all_dylibs[*]} " =~ " $ref_dylib " ]]; then + all_dylibs+=("$ref_dylib") + queue+=("$ref_dylib") + fi + done + done +} + +# Fix dylib install names +update_dylib_paths() { + local dylib_file="$1" + local path_prefix="$2" + echo "Fixing install names for $dylib_file..." + + # Update the dylib's own install name + local basename_dylib=$(basename "$dylib_file") + install_name_tool -id "${path_prefix}${basename_dylib}" "$dylib_file" 2>/dev/null || true + + otool -L "$dylib_file" | grep -v "$dylib_file" | awk '{print $1}' | while read -r dylib_path; do + if [[ "$dylib_path" != /usr/lib* ]] && [[ "$dylib_path" != /System/* ]]; then + local lib_name="${dylib_path##*/}" + local new_dylib_path="${path_prefix}${lib_name}" + echo " $dylib_path -> $new_dylib_path" + install_name_tool -change "$dylib_path" "$new_dylib_path" "$dylib_file" 2>/dev/null || true + fi + done + + # Re-sign with ad-hoc signature + codesign -fs- "$dylib_file" 2>/dev/null || true +} + +# Copy libraries to appropriate directories +copy_library() { + local lib="$1" + local gstreamer_dir="${ENGINE_DIR}/lib/gstreamer-1.0" + local lib_dir="${ENGINE_DIR}/lib" + + mkdir -p "$gstreamer_dir" "$lib_dir" + + if [[ "$lib" == *"/gstreamer-1.0/"* ]]; then + echo "Copying GStreamer plugin: $lib" + cp -L "$lib" "$gstreamer_dir/" + update_dylib_paths "$gstreamer_dir/$(basename "$lib")" "@loader_path/../" + else + echo "Copying library: $lib" + cp -L "$lib" "$lib_dir/" + update_dylib_paths "$lib_dir/$(basename "$lib")" "@loader_path/" + fi +} + +main() { + # Get Homebrew prefixes + GSTREAMER_PREFIX=$(brew --prefix gstreamer) + PREFIX=$(brew --prefix) + + echo "=== Finding GStreamer plugin dependencies ===" + for lib in "${GSTREAMER_LIBS[@]}"; do + dylib_path="${GSTREAMER_PREFIX}/lib/gstreamer-1.0/${lib}.dylib" + if [[ -f "$dylib_path" ]]; then + echo "Processing: $dylib_path" + find_dylib_dependencies "$dylib_path" + else + echo "Warning: $dylib_path not found" + fi + done + + echo "=== Finding library dependencies ===" + for lib in "${LIBS[@]}"; do + # Try with .dylib extension first, then without + dylib_path="${PREFIX}/lib/${lib}.dylib" + if [[ ! -f "$dylib_path" ]]; then + # Try finding the actual versioned dylib + dylib_path=$(find "${PREFIX}/lib" -maxdepth 1 -name "${lib}*.dylib" -type f 2>/dev/null | head -1) + fi + + if [[ -f "$dylib_path" ]]; then + echo "Processing: $dylib_path" + find_dylib_dependencies "$dylib_path" + else + echo "Warning: $lib not found in ${PREFIX}/lib" + fi + done + + echo "=== Copying ${#all_dylibs[@]} dylibs ===" + for dylib in "${all_dylibs[@]}"; do + copy_library "$dylib" + done + + # Copy GStreamer include files if they exist + if [[ -d "${GSTREAMER_PREFIX}/lib/gstreamer-1.0/include" ]]; then + echo "=== Copying GStreamer include files ===" + mkdir -p "${ENGINE_DIR}/lib/gstreamer-1.0" + cp -a "${GSTREAMER_PREFIX}/lib/gstreamer-1.0/include" "${ENGINE_DIR}/lib/gstreamer-1.0/" + fi + + echo "=== Fixing Wine .so files ===" + # Fix winegstreamer.so to find bundled libraries + if [[ -f "${ENGINE_DIR}/lib/wine/x86_64-unix/winegstreamer.so" ]]; then + update_dylib_paths "${ENGINE_DIR}/lib/wine/x86_64-unix/winegstreamer.so" "@rpath/" + fi + + # Fix other Wine .so files that might reference Homebrew libraries + for so_file in "${ENGINE_DIR}"/lib/wine/x86_64-unix/*.so; do + if [[ -f "$so_file" ]]; then + # Check if it has any non-system dependencies + if otool -L "$so_file" 2>/dev/null | grep -q "/usr/local\|/opt/homebrew"; then + echo "Fixing: $so_file" + update_dylib_paths "$so_file" "@rpath/" + fi + fi + done + + echo "=== Dylib bundling complete ===" +} + +main "$@" \ No newline at end of file From 4ff66ee5430b843fa1d3020b53705089b9b5912b Mon Sep 17 00:00:00 2001 From: esi <41133734+vapidinfinity@users.noreply.github.com> Date: Tue, 23 Dec 2025 18:10:32 +0100 Subject: [PATCH 02/15] fix: move dylib bundler back one directory i might genuinely be stupid committed from iphone --- .github/{workflows => }/dylib_bundler.zsh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/{workflows => }/dylib_bundler.zsh (99%) diff --git a/.github/workflows/dylib_bundler.zsh b/.github/dylib_bundler.zsh similarity index 99% rename from .github/workflows/dylib_bundler.zsh rename to .github/dylib_bundler.zsh index 4f2d1bb9ab66..5e698f975724 100644 --- a/.github/workflows/dylib_bundler.zsh +++ b/.github/dylib_bundler.zsh @@ -208,4 +208,4 @@ main() { echo "=== Dylib bundling complete ===" } -main "$@" \ No newline at end of file +main "$@" From 80c83d03076cb922435d12befc21448b8636e1f5 Mon Sep 17 00:00:00 2001 From: esi <41133734+vapidinfinity@users.noreply.github.com> Date: Tue, 23 Dec 2025 18:22:29 +0100 Subject: [PATCH 03/15] Update build.yml use ditto instead of cp for build artifact copying --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a65d259eb110..f11d105fe0e0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -149,7 +149,7 @@ jobs: run: | # copy wine installation mkdir -p Engine/wine - cp -R install/* Engine/wine + ditto --rsrc install Engine/wine - name: copy externals run: | From 25d2819d3b3ee830b06da254f1bdea07617f38fc Mon Sep 17 00:00:00 2001 From: esi <41133734+vapidinfinity@users.noreply.github.com> Date: Tue, 23 Dec 2025 20:43:43 +0100 Subject: [PATCH 04/15] fix(build): replace wine64 symlink with executable wrapper --- .github/workflows/build.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f11d105fe0e0..954430413b7c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -138,9 +138,17 @@ jobs: working-directory: build run: make install-lib DESTDIR=${{ github.workspace }}/install - - name: add wine64 symlink for backward compatibility + - name: add wine64 as an executable wrapper for backward compatibility working-directory: install/bin - run: ln -s wine wine64 + run: | + cat > wine64 << 'EOF' + #!/usr/bin/env bash + set -e + DIR="$(cd "$(dirname "$0")" && pwd)" + exec "$DIR/wine" "$@" + EOF + + chmod +x "$DIR/wine64" - name: create Engine directory run: mkdir -p Engine From 3926feef826f5fa52e61b2cca2decb65db73cd70 Mon Sep 17 00:00:00 2001 From: esi <41133734+vapidinfinity@users.noreply.github.com> Date: Tue, 23 Dec 2025 21:00:50 +0100 Subject: [PATCH 05/15] refactor(build): streamline dylib bundling process --- .github/dylib_bundler.zsh | 306 +++++++++++++++----------------------- 1 file changed, 121 insertions(+), 185 deletions(-) diff --git a/.github/dylib_bundler.zsh b/.github/dylib_bundler.zsh index 5e698f975724..0157e26eb218 100644 --- a/.github/dylib_bundler.zsh +++ b/.github/dylib_bundler.zsh @@ -1,211 +1,147 @@ #!/bin/zsh -# Bundle dylib dependencies for Wine distribution -# This script finds all dylib dependencies, copies them, and fixes install names +# Bundle dylib dependencies for Wine's distribution +# This script finds all dylib dependencies, copies them, and fixes install names. set -e # Output directory (can be overridden via environment variable) ENGINE_DIR="${ENGINE_DIR:-Engine/wine}" - -# GStreamer plugins to bundle -GSTREAMER_LIBS=( - "libgstapplemedia" - "libgstasf" - "libgstaudioconvert" - "libgstaudioparsers" - "libgstaudioresample" - "libgstavi" - "libgstcoreelements" - "libgstdebug" - "libgstdeinterlace" - "libgstid3demux" - "libgstisomp4" - "libgstlibav" - "libgstopengl" - "libgstplayback" - "libgsttypefindfunctions" - "libgstvideoconvertscale" - "libgstvideofilter" - "libgstvideoparsersbad" - "libgstwavparse" +BREW_PREFIX=$(brew --prefix) + +# List of GStreamer plugins to bundle, minus the 'libgst' prefix +GSTREAMER_PLUGINS=( + applemedia asf audioconvert audioparsers audioresample avi + coreelements debug deinterlace id3demux isomp4 libav opengl + playback typefindfunctions videoconvertscale videofilter + videoparsersbad wavparse ) -# Non-GStreamer libraries to bundle -LIBS=( - "libMoltenVK" - "libSDL2-2.0.0" - "libpcap" - "libfreetype" - "libgnutls" - "libpng16" - "libjpeg" - "libtiff" +# list of keg-only formulae and their main dylib names +BUNDLE_LIBS=( + molten-vk:libMoltenVK + sdl2:libSDL2-2.0.0 + freetype:libfreetype + gnutls:libgnutls + libpng:libpng16 + libtiff:libtiff + libpcap:libpcap + jpeg:libjpeg + libffi:libffi ) -# Global array to store all discovered dylibs (unique entries) -typeset -aU all_dylibs -# Queue for iterative processing -typeset -a queue +typeset -A seen_dylibs +typeset -a all_dylibs + +get_lib_path() { + local formula="$1" libname="$2" + local prefix=$(brew --prefix "$formula" 2>/dev/null) || return 1 + find "$prefix/lib" -maxdepth 1 -name "${libname}*.dylib" -type f 2>/dev/null | head -1 +} -# Resolve @rpath dependencies by searching in Homebrew's lib directory resolve_rpath() { - local ref_dylib="$1" - local dylib_name="${ref_dylib#@rpath/}" - local brew_lib_dir="$(brew --prefix)/lib" - local resolved_path="${brew_lib_dir}/${dylib_name}" - - if [[ -f "$resolved_path" ]]; then - echo "$resolved_path" - else - echo "" - fi + local name="${1#@rpath/}" + + # Check main lib dir first + [[ -f "${BREW_PREFIX}/lib/${name}" ]] && { echo "${BREW_PREFIX}/lib/${name}"; return; } + + # Search keg-only formula lib dirs + for entry in "${BUNDLE_LIBS[@]}"; do + local formula="${entry%%:*}" + local path="$(brew --prefix "$formula" 2>/dev/null)/lib/${name}" + [[ -f "$path" ]] && { echo "$path"; return; } + done } -# Find all dylib dependencies iteratively -find_dylib_dependencies() { - local dylib="$1" - queue+=("$dylib") - - while [[ ${#queue[@]} -gt 0 ]]; do - local current_dylib="${queue[1]}" - queue=("${queue[@]:1}") - - local referenced_dylibs=($(otool -L "$current_dylib" 2>/dev/null | awk '/^\t/ {print $1}' | grep '\.dylib')) - - for ref_dylib in $referenced_dylibs; do - # Skip system libraries - if [[ "$ref_dylib" == /usr/lib/* ]] || [[ "$ref_dylib" == /System/* ]]; then - continue - fi - - # Resolve @rpath references - if [[ "$ref_dylib" == @rpath/* ]]; then - ref_dylib=$(resolve_rpath "$ref_dylib") - if [[ -z "$ref_dylib" ]]; then - continue - fi - fi - - # Skip relative path references - if [[ "$ref_dylib" == @loader_path/* ]] || [[ "$ref_dylib" == @executable_path/* ]]; then - continue - fi - - # Add to array and queue if not already present - if [[ ! " ${all_dylibs[*]} " =~ " $ref_dylib " ]]; then - all_dylibs+=("$ref_dylib") - queue+=("$ref_dylib") - fi +normalize_path() { + python3 -c "import os; print(os.path.realpath('$1'))" 2>/dev/null || echo "$1" +} + +find_dependencies() { + local dylib="$1" + local norm=$(normalize_path "$dylib") + + [[ -n "${seen_dylibs[$norm]}" ]] && return + seen_dylibs[$norm]=1 + all_dylibs+=("$dylib") + + local -a queue=("$dylib") + + while [[ ${#queue[@]} -gt 0 ]]; do + local current="${queue[1]}" + queue=("${queue[@]:1}") + + for ref in $(otool -L "$current" 2>/dev/null | tail -n +2 | awk '/^\t/ {print $1}' | grep '\.dylib'); do + [[ "$ref" == /usr/lib/* || "$ref" == /System/* ]] && continue + [[ "$ref" == @loader_path/* || "$ref" == @executable_path/* ]] && continue + + [[ "$ref" == @rpath/* ]] && { ref=$(resolve_rpath "$ref"); [[ -z "$ref" ]] && continue; } + + norm=$(normalize_path "$ref") + [[ -z "${seen_dylibs[$norm]}" ]] && { + seen_dylibs[$norm]=1 + all_dylibs+=("$ref") + queue+=("$ref") + } + done done - done } -# Fix dylib install names -update_dylib_paths() { - local dylib_file="$1" - local path_prefix="$2" - echo "Fixing install names for $dylib_file..." - - # Update the dylib's own install name - local basename_dylib=$(basename "$dylib_file") - install_name_tool -id "${path_prefix}${basename_dylib}" "$dylib_file" 2>/dev/null || true - - otool -L "$dylib_file" | grep -v "$dylib_file" | awk '{print $1}' | while read -r dylib_path; do - if [[ "$dylib_path" != /usr/lib* ]] && [[ "$dylib_path" != /System/* ]]; then - local lib_name="${dylib_path##*/}" - local new_dylib_path="${path_prefix}${lib_name}" - echo " $dylib_path -> $new_dylib_path" - install_name_tool -change "$dylib_path" "$new_dylib_path" "$dylib_file" 2>/dev/null || true - fi - done - - # Re-sign with ad-hoc signature - codesign -fs- "$dylib_file" 2>/dev/null || true +fix_install_names() { + local file="$1" prefix="$2" + chmod u+w "$file" + install_name_tool -id "${prefix}$(basename "$file")" "$file" 2>/dev/null || true + + otool -L "$file" | grep -v "$file" | awk '{print $1}' | while read -r path; do + [[ "$path" != /usr/lib* && "$path" != /System/* ]] && \ + install_name_tool -change "$path" "${prefix}${path##*/}" "$file" 2>/dev/null || true + done + codesign -fs- "$file" 2>/dev/null || true } -# Copy libraries to appropriate directories -copy_library() { - local lib="$1" - local gstreamer_dir="${ENGINE_DIR}/lib/gstreamer-1.0" - local lib_dir="${ENGINE_DIR}/lib" - - mkdir -p "$gstreamer_dir" "$lib_dir" - - if [[ "$lib" == *"/gstreamer-1.0/"* ]]; then - echo "Copying GStreamer plugin: $lib" - cp -L "$lib" "$gstreamer_dir/" - update_dylib_paths "$gstreamer_dir/$(basename "$lib")" "@loader_path/../" - else - echo "Copying library: $lib" - cp -L "$lib" "$lib_dir/" - update_dylib_paths "$lib_dir/$(basename "$lib")" "@loader_path/" - fi +copy_dylib() { + local lib="$1" dest_dir="${ENGINE_DIR}/lib" prefix="@loader_path/" + + [[ "$lib" == *"/gstreamer-1.0/"* ]] && { dest_dir="${ENGINE_DIR}/lib/gstreamer-1.0"; prefix="@loader_path/../"; } + + local dest="${dest_dir}/$(basename "$lib")" + mkdir -p "$dest_dir" + [[ -f "$dest" ]] && return 0 + + cp -L "$lib" "$dest" + fix_install_names "$dest" "$prefix" } main() { - # Get Homebrew prefixes - GSTREAMER_PREFIX=$(brew --prefix gstreamer) - PREFIX=$(brew --prefix) - - echo "=== Finding GStreamer plugin dependencies ===" - for lib in "${GSTREAMER_LIBS[@]}"; do - dylib_path="${GSTREAMER_PREFIX}/lib/gstreamer-1.0/${lib}.dylib" - if [[ -f "$dylib_path" ]]; then - echo "Processing: $dylib_path" - find_dylib_dependencies "$dylib_path" - else - echo "Warning: $dylib_path not found" - fi - done - - echo "=== Finding library dependencies ===" - for lib in "${LIBS[@]}"; do - # Try with .dylib extension first, then without - dylib_path="${PREFIX}/lib/${lib}.dylib" - if [[ ! -f "$dylib_path" ]]; then - # Try finding the actual versioned dylib - dylib_path=$(find "${PREFIX}/lib" -maxdepth 1 -name "${lib}*.dylib" -type f 2>/dev/null | head -1) - fi - - if [[ -f "$dylib_path" ]]; then - echo "Processing: $dylib_path" - find_dylib_dependencies "$dylib_path" - else - echo "Warning: $lib not found in ${PREFIX}/lib" - fi - done - - echo "=== Copying ${#all_dylibs[@]} dylibs ===" - for dylib in "${all_dylibs[@]}"; do - copy_library "$dylib" - done - - # Copy GStreamer include files if they exist - if [[ -d "${GSTREAMER_PREFIX}/lib/gstreamer-1.0/include" ]]; then - echo "=== Copying GStreamer include files ===" - mkdir -p "${ENGINE_DIR}/lib/gstreamer-1.0" - cp -a "${GSTREAMER_PREFIX}/lib/gstreamer-1.0/include" "${ENGINE_DIR}/lib/gstreamer-1.0/" - fi - - echo "=== Fixing Wine .so files ===" - # Fix winegstreamer.so to find bundled libraries - if [[ -f "${ENGINE_DIR}/lib/wine/x86_64-unix/winegstreamer.so" ]]; then - update_dylib_paths "${ENGINE_DIR}/lib/wine/x86_64-unix/winegstreamer.so" "@rpath/" - fi - - # Fix other Wine .so files that might reference Homebrew libraries - for so_file in "${ENGINE_DIR}"/lib/wine/x86_64-unix/*.so; do - if [[ -f "$so_file" ]]; then - # Check if it has any non-system dependencies - if otool -L "$so_file" 2>/dev/null | grep -q "/usr/local\|/opt/homebrew"; then - echo "Fixing: $so_file" - update_dylib_paths "$so_file" "@rpath/" - fi - fi - done - - echo "=== Dylib bundling complete ===" + local gst_prefix=$(brew --prefix gstreamer) + + echo "=== Processing GStreamer plugins ===" + for plugin in "${GSTREAMER_PLUGINS[@]}"; do + local path="${gst_prefix}/lib/gstreamer-1.0/libgst${plugin}.dylib" + [[ -f "$path" ]] && find_dependencies "$path" || echo "Warning: $plugin not found" + done + + echo "=== Processing libraries ===" + for entry in "${BUNDLE_LIBS[@]}"; do + local formula="${entry%%:*}" libname="${entry#*:}" + local path=$(get_lib_path "$formula" "$libname") + [[ -n "$path" ]] && find_dependencies "$path" || echo "Warning: $formula not found" + done + + echo "=== Copying ${#all_dylibs[@]} dylibs ===" + for dylib in "${all_dylibs[@]}"; do copy_dylib "$dylib"; done + + [[ -d "${gst_prefix}/lib/gstreamer-1.0/include" ]] && { + mkdir -p "${ENGINE_DIR}/lib/gstreamer-1.0" + cp -a "${gst_prefix}/lib/gstreamer-1.0/include" "${ENGINE_DIR}/lib/gstreamer-1.0/" + } + + echo "=== Fixing Wine .so files ===" + for so in "${ENGINE_DIR}"/lib/wine/x86_64-unix/*.so(N); do + otool -L "$so" 2>/dev/null | grep -q "/usr/local\|/opt/homebrew" && fix_install_names "$so" "@rpath/" + done + + echo "=== Done: ${#all_dylibs[@]} dylibs bundled ===" } main "$@" From 9bb34c9e0b57ffe99d7da107009c024e9d7e9e73 Mon Sep 17 00:00:00 2001 From: esi <41133734+vapidinfinity@users.noreply.github.com> Date: Tue, 23 Dec 2025 21:33:32 +0100 Subject: [PATCH 06/15] feat(build): include wine mono --- .github/workflows/build.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 954430413b7c..547c47abead9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -150,12 +150,18 @@ jobs: chmod +x "$DIR/wine64" + - name: install wine mono + working-directory: install/share/wine + run: | + mkdir -p mono + curl -fL https://github.com/wine-mono/wine-mono/releases/download/wine-mono-8.1.0/wine-mono-8.1.0-x86.tar.xz + | tar -xJ -C mono + - name: create Engine directory run: mkdir -p Engine - name: copy build artifacts run: | - # copy wine installation mkdir -p Engine/wine ditto --rsrc install Engine/wine From 2565c8208baac4d030d9e4896d82e86b1b78993c Mon Sep 17 00:00:00 2001 From: esi <41133734+vapidinfinity@users.noreply.github.com> Date: Tue, 23 Dec 2025 22:07:32 +0100 Subject: [PATCH 07/15] fix(build): update bad chmod command for wine64 executable wrapper --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 547c47abead9..4dcf93d8ebb0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -148,7 +148,7 @@ jobs: exec "$DIR/wine" "$@" EOF - chmod +x "$DIR/wine64" + chmod +x wine64 - name: install wine mono working-directory: install/share/wine From 88d7fb7dd798d6bd85d71fed12c713e365273a0d Mon Sep 17 00:00:00 2001 From: esi <41133734+vapidinfinity@users.noreply.github.com> Date: Tue, 23 Dec 2025 22:37:52 +0100 Subject: [PATCH 08/15] chore(build): add comment to wine64 executable wrapper --- .github/workflows/build.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4dcf93d8ebb0..4cab5c4c9a2f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -143,6 +143,10 @@ jobs: run: | cat > wine64 << 'EOF' #!/usr/bin/env bash + + # this is a wrapper created for Mythic to forward `wine64` calls to `wine`. + # for older versions of Mythic, which expected a wine64 binary to be present. + set -e DIR="$(cd "$(dirname "$0")" && pwd)" exec "$DIR/wine" "$@" From 195fa3a3123f017bb65d0810885b4ca0b8ee338d Mon Sep 17 00:00:00 2001 From: esi <41133734+vapidinfinity@users.noreply.github.com> Date: Tue, 23 Dec 2025 22:41:43 +0100 Subject: [PATCH 09/15] chore(build): remove unneeded `-p` argument for relevant `mkdir`s --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4cab5c4c9a2f..c66af8b81b5d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -87,7 +87,7 @@ jobs: brew install local/mingw-w64/mingw-w64 - name: create build directory - run: mkdir -p build + run: mkdir build - name: configure wine working-directory: build @@ -132,7 +132,7 @@ jobs: run: make -j$(sysctl -n hw.ncpu) - name: create install directory - run: mkdir -p install + run: mkdir install - name: install wine working-directory: build @@ -162,7 +162,7 @@ jobs: | tar -xJ -C mono - name: create Engine directory - run: mkdir -p Engine + run: mkdir Engine - name: copy build artifacts run: | From 6897e61281cd707e83dbed16d114e17f5b2839b5 Mon Sep 17 00:00:00 2001 From: esi <41133734+vapidinfinity@users.noreply.github.com> Date: Tue, 23 Dec 2025 22:46:59 +0100 Subject: [PATCH 10/15] chore(build): tidy up comments --- .github/dylib_bundler.zsh | 26 ++++++++++++++++++++------ .github/workflows/build.yml | 2 +- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/.github/dylib_bundler.zsh b/.github/dylib_bundler.zsh index 0157e26eb218..116836f7c7f1 100644 --- a/.github/dylib_bundler.zsh +++ b/.github/dylib_bundler.zsh @@ -1,7 +1,6 @@ #!/bin/zsh -# Bundle dylib dependencies for Wine's distribution -# This script finds all dylib dependencies, copies them, and fixes install names. +# this is a script created for Mythic to bundle its dependencies' dylibs and copy them to the appropriate location. set -e @@ -11,10 +10,25 @@ BREW_PREFIX=$(brew --prefix) # List of GStreamer plugins to bundle, minus the 'libgst' prefix GSTREAMER_PLUGINS=( - applemedia asf audioconvert audioparsers audioresample avi - coreelements debug deinterlace id3demux isomp4 libav opengl - playback typefindfunctions videoconvertscale videofilter - videoparsersbad wavparse + applemedia + asf + audioconvert + audioparsers + audioresample + avi + coreelements + debug + deinterlace + id3demux + isomp4 + libav + opengl + playback + typefindfunctions + videoconvertscale + videofilter + videoparsersbad + wavparse ) # list of keg-only formulae and their main dylib names diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c66af8b81b5d..faddae911ae7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,7 +7,7 @@ on: env: MACOSX_DEPLOYMENT_TARGET: 10.15 SDKROOT: /Library/Developer/CommandLineTools/SDKs/MacOSX12.3.sdk - TOOLCHAINS: com.applex.dt.toolchain.Xcode13 + TOOLCHAINS: com.applex.dt.toolchain.Xcode13 # from gcenx PATH: /usr/local/bin:/usr/local/opt/bison/bin:/usr/bin:/bin:/usr/sbin:/sbin From 79e5dd4bdddc514b0f62797a4af21fc5c1e00cc3 Mon Sep 17 00:00:00 2001 From: esi <41133734+vapidinfinity@users.noreply.github.com> Date: Tue, 23 Dec 2025 23:04:14 +0100 Subject: [PATCH 11/15] genius was calling. i declined --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index faddae911ae7..80cc0ae37d44 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -158,7 +158,7 @@ jobs: working-directory: install/share/wine run: | mkdir -p mono - curl -fL https://github.com/wine-mono/wine-mono/releases/download/wine-mono-8.1.0/wine-mono-8.1.0-x86.tar.xz + curl -fL https://github.com/wine-mono/wine-mono/releases/download/wine-mono-8.1.0/wine-mono-8.1.0-x86.tar.xz \ | tar -xJ -C mono - name: create Engine directory From d50ee7775f41ded308fac56d1ecd39a4498777f7 Mon Sep 17 00:00:00 2001 From: esi <41133734+vapidinfinity@users.noreply.github.com> Date: Wed, 24 Dec 2025 08:45:27 +0100 Subject: [PATCH 12/15] fix(dylib_bundler): rename path variable due to conflicts --- .github/dylib_bundler.zsh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/dylib_bundler.zsh b/.github/dylib_bundler.zsh index 116836f7c7f1..2317f549dfaf 100644 --- a/.github/dylib_bundler.zsh +++ b/.github/dylib_bundler.zsh @@ -62,8 +62,8 @@ resolve_rpath() { # Search keg-only formula lib dirs for entry in "${BUNDLE_LIBS[@]}"; do local formula="${entry%%:*}" - local path="$(brew --prefix "$formula" 2>/dev/null)/lib/${name}" - [[ -f "$path" ]] && { echo "$path"; return; } + local lib_path="$(brew --prefix "$formula" 2>/dev/null)/lib/${name}" + [[ -f "$lib_path" ]] && { echo "$lib_path"; return; } done } @@ -106,9 +106,9 @@ fix_install_names() { chmod u+w "$file" install_name_tool -id "${prefix}$(basename "$file")" "$file" 2>/dev/null || true - otool -L "$file" | grep -v "$file" | awk '{print $1}' | while read -r path; do - [[ "$path" != /usr/lib* && "$path" != /System/* ]] && \ - install_name_tool -change "$path" "${prefix}${path##*/}" "$file" 2>/dev/null || true + otool -L "$file" | grep -v "$file" | awk '{print $1}' | while read -r lib_path; do + [[ "$lib_path" != /usr/lib* && "$lib_path" != /System/* ]] && \ + install_name_tool -change "$lib_path" "${prefix}${lib_path##*/}" "$file" 2>/dev/null || true done codesign -fs- "$file" 2>/dev/null || true } @@ -131,15 +131,15 @@ main() { echo "=== Processing GStreamer plugins ===" for plugin in "${GSTREAMER_PLUGINS[@]}"; do - local path="${gst_prefix}/lib/gstreamer-1.0/libgst${plugin}.dylib" - [[ -f "$path" ]] && find_dependencies "$path" || echo "Warning: $plugin not found" + local lib_path="${gst_prefix}/lib/gstreamer-1.0/libgst${plugin}.dylib" + [[ -f "$lib_path" ]] && find_dependencies "$lib_path" || echo "Warning: $plugin not found" done echo "=== Processing libraries ===" for entry in "${BUNDLE_LIBS[@]}"; do local formula="${entry%%:*}" libname="${entry#*:}" - local path=$(get_lib_path "$formula" "$libname") - [[ -n "$path" ]] && find_dependencies "$path" || echo "Warning: $formula not found" + local lib_path=$(get_lib_path "$formula" "$libname") + [[ -n "$lib_path" ]] && find_dependencies "$lib_path" || echo "Warning: $formula not found" done echo "=== Copying ${#all_dylibs[@]} dylibs ===" From f70f4fa63f271174c593794340641bec4bae3085 Mon Sep 17 00:00:00 2001 From: esi <41133734+vapidinfinity@users.noreply.github.com> Date: Wed, 24 Dec 2025 11:13:49 +0100 Subject: [PATCH 13/15] refactor(build): use all codes during engine artifact compression --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 80cc0ae37d44..15fd4fe4ad7b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -187,7 +187,7 @@ jobs: run: cp -R src/Mythic/Properties.plist Engine/ - name: compress engine artifact - run: tar -cJf Engine.tar.xz -C Engine . + run: tar -cf Engine.tar.xz -C Engine --use-compress-program="xz -6 -T0" . - name: upload engine artifact uses: actions/upload-artifact@v5 From ee6fcae20532993ee3ca3094e0f5ba7b5bda8330 Mon Sep 17 00:00:00 2001 From: esi <41133734+vapidinfinity@users.noreply.github.com> Date: Wed, 24 Dec 2025 11:18:22 +0100 Subject: [PATCH 14/15] feat(build): include wine gecko --- .github/workflows/build.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 15fd4fe4ad7b..d9112ca788fb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -161,6 +161,13 @@ jobs: curl -fL https://github.com/wine-mono/wine-mono/releases/download/wine-mono-8.1.0/wine-mono-8.1.0-x86.tar.xz \ | tar -xJ -C mono + - name: install wine gecko + working-directory: install/share/wine + run: | + mkdir -p gecko + curl -fL https://dl.winehq.org/wine/wine-gecko/2.47.4/wine-gecko-2.47.4-x86.tar.xz \ + | tar -xJ -C gecko + - name: create Engine directory run: mkdir Engine From 80dfcda4c00f22c575822df54f56af33533fb28b Mon Sep 17 00:00:00 2001 From: esi <41133734+vapidinfinity@users.noreply.github.com> Date: Wed, 24 Dec 2025 15:34:36 +0100 Subject: [PATCH 15/15] fix(build): increase compression level for engine artifact --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d9112ca788fb..3cd6109a0c7c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -194,7 +194,7 @@ jobs: run: cp -R src/Mythic/Properties.plist Engine/ - name: compress engine artifact - run: tar -cf Engine.tar.xz -C Engine --use-compress-program="xz -6 -T0" . + run: tar -cf Engine.tar.xz -C Engine --use-compress-program="xz -9 -T0" . - name: upload engine artifact uses: actions/upload-artifact@v5