diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index b0913348c..11d3d799c 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -147,6 +147,18 @@ jobs: -p:PublishSingleFile=true \ -o Launcher/artifacts/macos/translator-x86_64 + - name: Publish self-contained setup CLI + shell: bash + run: | + dotnet publish Launcher/WiiCompiled.Setup.Linux/WiiCompiled.Setup.Linux.csproj \ + -c Release -r osx-arm64 --self-contained true \ + -p:PublishSingleFile=true \ + -o Launcher/artifacts/macos/setup-arm64 + dotnet publish Launcher/WiiCompiled.Setup.Linux/WiiCompiled.Setup.Linux.csproj \ + -c Release -r osx-x64 --self-contained true \ + -p:PublishSingleFile=true \ + -o Launcher/artifacts/macos/setup-x86_64 + - name: Download pinned universal Ninja shell: bash run: | @@ -189,10 +201,13 @@ jobs: --nodtool-x86_64 Launcher/artifacts/macos/nodtool-x86_64 \ --translator-arm64 Launcher/artifacts/macos/translator-arm64/Translator.Cli \ --translator-x86_64 Launcher/artifacts/macos/translator-x86_64/Translator.Cli \ + --setup-arm64 Launcher/artifacts/macos/setup-arm64/WiiCompiled.Setup.Linux \ + --setup-x86_64 Launcher/artifacts/macos/setup-x86_64/WiiCompiled.Setup.Linux \ --cmake-root Launcher/artifacts/macos/cmake \ --ninja-arm64 Launcher/artifacts/macos/ninja/ninja \ --ninja-x86_64 Launcher/artifacts/macos/ninja/ninja \ --output Launcher/dist/WiiCompiled-Setup.pkg \ + --run-output Launcher/dist/WiiCompiled-Setup-macos.run \ ${package_version:+--version "$package_version"} - name: Verify package layout and architecture-specific tools @@ -215,6 +230,16 @@ jobs: lipo "$resources/tools/cmake/bin/cmake" -verify_arch arm64 x86_64 bash "$resources/setup.command" --help /usr/bin/arch -x86_64 /bin/bash "$resources/setup.command" --help + # The .run must answer --version without unpacking, then unpack once and run its entry point + # with each architecture's setup CLI. + run=Launcher/dist/WiiCompiled-Setup-macos.run + version=$("$run" --version) + HOME="$RUNNER_TEMP/run-home" "$run" check-products + unpacked="$RUNNER_TEMP/run-home/Library/Application Support/WiiCompiled/Setup/$version" + for arch in arm64 x86_64; do + lipo "$unpacked/tools/$arch/wiicompiled-setup" -verify_arch "$arch" + done + HOME="$RUNNER_TEMP/run-home" /usr/bin/arch -x86_64 /bin/bash "$run" check-products - uses: actions/upload-artifact@v7 with: @@ -223,6 +248,13 @@ jobs: if-no-files-found: error archive: false + - uses: actions/upload-artifact@v7 + with: + name: WiiCompiled-Setup-macos-run + path: Launcher/dist/WiiCompiled-Setup-macos.run + if-no-files-found: error + archive: false + # Publishes the packaged installers as a GitHub Release whenever a v* tag is pushed. Wheel Wizard # discovers updates from these releases, so the contract it relies on is enforced here: a full # (non-prerelease) release whose tag is v, carrying the expected platform assets, @@ -275,7 +307,7 @@ jobs: set -euo pipefail ls -lR artifacts assets=() - for name in WiiCompiled-Setup.exe WiiCompiled-Setup-x86_64.AppImage WiiCompiled-Setup-aarch64.AppImage WiiCompiled-Setup.pkg; do + for name in WiiCompiled-Setup.exe WiiCompiled-Setup-x86_64.AppImage WiiCompiled-Setup-aarch64.AppImage WiiCompiled-Setup.pkg WiiCompiled-Setup-macos.run; do found="$(find artifacts -type f -name "$name" | head -n 1)" [ -n "$found" ] && [ -s "$found" ] || { echo "::error::missing release asset $name"; exit 1; } assets+=("$found") diff --git a/.gitignore b/.gitignore index 704d29c72..2f047d63f 100644 --- a/.gitignore +++ b/.gitignore @@ -27,7 +27,7 @@ Code.pul /build/ /build-*/ /native-build/ -/native-build-macos/ +/native-build-macos*/ /local-products/ /dist/ /out/ diff --git a/Launcher/WiiCompiled.Setup.Common/NodToolProvider.cs b/Launcher/WiiCompiled.Setup.Common/NodToolProvider.cs index f58769565..cdee6e3dc 100644 --- a/Launcher/WiiCompiled.Setup.Common/NodToolProvider.cs +++ b/Launcher/WiiCompiled.Setup.Common/NodToolProvider.cs @@ -56,6 +56,15 @@ private static string AssetName() var other => throw new PlatformNotSupportedException($"No prebuilt nodtool release for Windows {other}"), }; } + if (OperatingSystem.IsMacOS()) + { + return RuntimeInformation.OSArchitecture switch + { + Architecture.X64 => "nodtool-macos-x86_64", + Architecture.Arm64 => "nodtool-macos-arm64", + var other => throw new PlatformNotSupportedException($"No prebuilt nodtool release for macOS {other}"), + }; + } return RuntimeInformation.OSArchitecture switch { Architecture.X64 => "nodtool-linux-x86_64", diff --git a/Launcher/WiiCompiled.Setup.Linux/BuildRunner.cs b/Launcher/WiiCompiled.Setup.Linux/BuildRunner.cs index 292afd943..218da8dc1 100644 --- a/Launcher/WiiCompiled.Setup.Linux/BuildRunner.cs +++ b/Launcher/WiiCompiled.Setup.Linux/BuildRunner.cs @@ -17,8 +17,11 @@ public static async Task RunAsync( IInstallReporter reporter, CancellationToken cancellationToken) { - var script = Path.Combine(workspace, "Launcher", "local-build.sh"); - if (!File.Exists(script)) throw new FileNotFoundException("local-build.sh is missing", script); + // macOS has its own build script (clang from Xcode, .app bundles) that takes the same flags, + // minus the Linux-only toolchain overrides below, which it rejects as unknown options. + var script = Path.Combine(workspace, "Launcher", + OperatingSystem.IsMacOS() ? "local-build-macos.command" : "local-build.sh"); + if (!File.Exists(script)) throw new FileNotFoundException($"{Path.GetFileName(script)} is missing", script); var startInfo = new ProcessStartInfo("bash") { @@ -106,7 +109,7 @@ public static async Task RunAsync( if (process.ExitCode != 0) { - throw new InvalidOperationException($"local-build.sh failed (exit {process.ExitCode}). See diagnostics above."); + throw new InvalidOperationException($"{Path.GetFileName(script)} failed (exit {process.ExitCode}). See diagnostics above."); } } diff --git a/Launcher/WiiCompiled.Setup.Linux/DesktopEntry.cs b/Launcher/WiiCompiled.Setup.Linux/DesktopEntry.cs index 6ae642638..990bacc5a 100644 --- a/Launcher/WiiCompiled.Setup.Linux/DesktopEntry.cs +++ b/Launcher/WiiCompiled.Setup.Linux/DesktopEntry.cs @@ -15,6 +15,8 @@ private static string PathFor(string profile) => public static void Create(string profile, string displayName, string exePath) { + // macOS has no freedesktop menu; the installed .app bundle is the launchable entry itself. + if (OperatingSystem.IsMacOS()) return; // exePath is the installed native runtime binary itself (e.g. // .../Install/Base/WiiCompiled) - each profile already gets its own .desktop file here, // so there is no need to route through the setup tool's own launch-base/launch-retro diff --git a/Launcher/WiiCompiled.Setup.Linux/Program.cs b/Launcher/WiiCompiled.Setup.Linux/Program.cs index 75cc9de2a..3eea85ba5 100644 --- a/Launcher/WiiCompiled.Setup.Linux/Program.cs +++ b/Launcher/WiiCompiled.Setup.Linux/Program.cs @@ -200,7 +200,9 @@ await BuildRunner.RunAsync( foreach (var p in profiles) { var dir = p == "base" ? (baseInstallDir ?? installDir) : installDir; - var exeName = p == "base" ? "WiiCompiled" : "RetroRewind"; + var product = p == "base" ? "WiiCompiled" : "RetroRewind"; + // macOS builds a .app bundle (publish-app.command); launch/check-products want the binary inside it. + var exeName = OperatingSystem.IsMacOS() ? $"{product}.app/Contents/MacOS/{product}" : product; var displayName = p == "base" ? "WiiCompiled (base game)" : "WiiCompiled (Retro Rewind)"; state.Products.RemoveAll(r => r.Profile == p); state.Products.Add(new ProductInstallRecord diff --git a/Launcher/WiiCompiled.Setup.Linux/WiiCompiled.Setup.Linux.csproj b/Launcher/WiiCompiled.Setup.Linux/WiiCompiled.Setup.Linux.csproj index bb01a115c..e84ae308a 100644 --- a/Launcher/WiiCompiled.Setup.Linux/WiiCompiled.Setup.Linux.csproj +++ b/Launcher/WiiCompiled.Setup.Linux/WiiCompiled.Setup.Linux.csproj @@ -8,7 +8,7 @@ WiiCompiled.Setup.Linux patchzy WiiCompiled - Command-line installer and launcher for WiiCompiled on Linux + Command-line installer and launcher for WiiCompiled on Linux and macOS embedded en true diff --git a/Launcher/local-build-macos.command b/Launcher/local-build-macos.command index 8a8679da6..21306d180 100755 --- a/Launcher/local-build-macos.command +++ b/Launcher/local-build-macos.command @@ -190,6 +190,22 @@ step configure-native 'Configuring the native toolchain' mkw_write_identity "$toolchain_provenance" ToolchainFingerprint "$toolchain_fingerprint" targets=(); [[ "$profile" != retro-rewind ]] && targets+=(WiiCompiled); [[ "$profile" != base ]] && targets+=(RetroRewind) step compile "Compiling ${targets[*]} locally"; "$cmake_bin" --build "$native_build" --target "${targets[@]}" --parallel "$global_jobs" -if [[ "$profile" != retro-rewind ]]; then "$script_dir/macos/publish-app.command" --build-dir "$native_build" --product WiiCompiled --output-dir "${base_output_dir:-$output_dir}" --architecture "$macos_arch" --minimum-system-version "$macos_deployment_target"; fi -if (( builds_retro )); then "$script_dir/macos/publish-app.command" --build-dir "$native_build" --product RetroRewind --output-dir "$output_dir" --architecture "$macos_arch" --minimum-system-version "$macos_deployment_target"; fi +# Same provenance record local-build.sh writes; Wheel Wizard reads CodePulSha256 to tell whether Retro Rewind is current. +write_build_record() { + local code_pul_sha=null + [[ "$2" == retro-rewind ]] && code_pul_sha="\"$(mkw_sha256 "$retro_root/Binaries/Code.pul")\"" + cat > "$1/local-build.json" <&2; exit 1; } copy_clean() { DITTONORSRC=1 ditto --norsrc --noqtn "$@"; } usage() { cat <<'EOF' -Usage: build-setup-pkg.command --nodtool-arm64 PATH --nodtool-x86_64 PATH --translator-arm64 PATH --translator-x86_64 PATH --cmake-root DIR --ninja-arm64 PATH --ninja-x86_64 PATH --output PKG [options] +Usage: build-setup-pkg.command --nodtool-arm64 PATH --nodtool-x86_64 PATH --translator-arm64 PATH --translator-x86_64 PATH --setup-arm64 PATH --setup-x86_64 PATH --cmake-root DIR --ninja-arm64 PATH --ninja-x86_64 PATH --output PKG [options] Creates a game-code-free WiiCompiled Setup.pkg. The supplied tools must be maintainer-verified, redistributable macOS artifacts for both arm64 and @@ -22,11 +22,12 @@ Developer ID Installer certificate. --workspace DIR Repository root (default: script's grandparent) --version VERSION Bundle/package version (default: project version, or 0.1.0) --installer-identity NAME Developer ID Installer identity for productbuild + --run-output FILE Also write the same bundle as a self-extracting .run for frontends EOF } script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) -workspace=$(cd "$script_dir/../.." && pwd); nodtool_arm64=""; nodtool_x86_64=""; translator_arm64=""; translator_x86_64=""; cmake_root=""; ninja_arm64=""; ninja_x86_64=""; output=""; version=0.1.0; identity="" +workspace=$(cd "$script_dir/../.." && pwd); nodtool_arm64=""; nodtool_x86_64=""; translator_arm64=""; translator_x86_64=""; setup_arm64=""; setup_x86_64=""; cmake_root=""; ninja_arm64=""; ninja_x86_64=""; output=""; version=0.1.0; identity=""; run_output="" version_supplied=false while (($#)); do case "$1" in @@ -35,12 +36,15 @@ while (($#)); do --nodtool-x86_64) nodtool_x86_64=${2:-}; shift 2 ;; --translator-arm64) translator_arm64=${2:-}; shift 2 ;; --translator-x86_64) translator_x86_64=${2:-}; shift 2 ;; + --setup-arm64) setup_arm64=${2:-}; shift 2 ;; + --setup-x86_64) setup_x86_64=${2:-}; shift 2 ;; --cmake-root) cmake_root=${2:-}; shift 2 ;; --ninja-arm64) ninja_arm64=${2:-}; shift 2 ;; --ninja-x86_64) ninja_x86_64=${2:-}; shift 2 ;; --output) output=${2:-}; shift 2 ;; --version) version=${2:-}; version_supplied=true; shift 2 ;; --installer-identity) identity=${2:-}; shift 2 ;; + --run-output) run_output=${2:-}; shift 2 ;; -h|--help) usage; exit 0 ;; *) fail "unknown option: $1" ;; esac @@ -59,7 +63,7 @@ fi IFS=. read -r version_major version_minor version_patch <<< "$version" short_version="$version_major.${version_minor:-0}.${version_patch:-0}" for tool in pkgbuild productbuild ditto codesign lipo; do command -v "$tool" >/dev/null || fail "required macOS tool unavailable: $tool"; done -for tool_path in "$nodtool_arm64" "$nodtool_x86_64" "$translator_arm64" "$translator_x86_64" "$ninja_arm64" "$ninja_x86_64"; do [[ -x "$tool_path" ]] || fail 'each architecture-specific tool must name an executable'; done +for tool_path in "$nodtool_arm64" "$nodtool_x86_64" "$translator_arm64" "$translator_x86_64" "$setup_arm64" "$setup_x86_64" "$ninja_arm64" "$ninja_x86_64"; do [[ -x "$tool_path" ]] || fail 'each architecture-specific tool must name an executable'; done [[ -x "$cmake_root/bin/cmake" ]] || fail '--cmake-root must contain bin/cmake' require_arch() { local artifact=$1 arch=$2 label=$3 @@ -67,6 +71,7 @@ require_arch() { } require_arch "$nodtool_arm64" arm64 '--nodtool-arm64'; require_arch "$nodtool_x86_64" x86_64 '--nodtool-x86_64' require_arch "$translator_arm64" arm64 '--translator-arm64'; require_arch "$translator_x86_64" x86_64 '--translator-x86_64' +require_arch "$setup_arm64" arm64 '--setup-arm64'; require_arch "$setup_x86_64" x86_64 '--setup-x86_64' require_arch "$ninja_arm64" arm64 '--ninja-arm64'; require_arch "$ninja_x86_64" x86_64 '--ninja-x86_64' lipo "$cmake_root/bin/cmake" -verify_arch arm64 x86_64 >/dev/null 2>&1 || fail '--cmake-root/bin/cmake must be universal2' @@ -91,12 +96,13 @@ run_for_arch() { } for arch in arm64 x86_64; do if [[ "$arch" == arm64 ]]; then - nodtool=$nodtool_arm64; translator=$translator_arm64; ninja=$ninja_arm64 + nodtool=$nodtool_arm64; translator=$translator_arm64; setup=$setup_arm64; ninja=$ninja_arm64 else - nodtool=$nodtool_x86_64; translator=$translator_x86_64; ninja=$ninja_x86_64 + nodtool=$nodtool_x86_64; translator=$translator_x86_64; setup=$setup_x86_64; ninja=$ninja_x86_64 fi run_for_arch "$arch" "--nodtool-$arch" "$nodtool" --version run_for_arch "$arch" "--translator-$arch" "$translator" --help + run_for_arch "$arch" "--setup-$arch" "$setup" --version run_for_arch "$arch" "--ninja-$arch" "$ninja" --version done run_for_arch "$host_arch" '--cmake-root/bin/cmake' "$cmake_root/bin/cmake" --version @@ -143,6 +149,7 @@ APPLESCRIPT EOF chmod +x "$app/Contents/MacOS/WiiCompiledSetup" copy_clean "$script_dir/setup.command" "$resources/setup.command"; chmod +x "$resources/setup.command" +copy_clean "$script_dir/sync-workspace.command" "$resources/sync-workspace.command"; chmod +x "$resources/sync-workspace.command" # Copy only the build inputs. This deliberately avoids a maintainer's ignored # output directories, local disc extraction, and developer-only packaging. mkdir -p "$resources/workspace" @@ -181,6 +188,24 @@ copy_clean "$ninja_x86_64" "$resources/tools/x86_64/ninja"; chmod +x "$resources copy_clean "$workspace/LICENSE" "$resources/LICENSE" copy_clean "$workspace/THIRD-PARTY-NOTICES.md" "$resources/THIRD-PARTY-NOTICES.md" codesign --force --deep --sign - "$app" +if [[ -n "$run_output" ]]; then + # The same signed Resources plus the setup CLI and its wiicompiled-setup entry point, behind + # setup-run-header.sh, so Wheel Wizard can download and run it without installing the pkg. Only + # the .run carries the CLI; the pkg's own setup.command never uses it. + run_output=$(cd "$(dirname "$run_output")" && pwd)/$(basename "$run_output") + run_extra="$stage/run-extra" + mkdir -p "$run_extra/tools/arm64" "$run_extra/tools/x86_64" + copy_clean "$script_dir/wiicompiled-setup.command" "$run_extra/wiicompiled-setup" + copy_clean "$setup_arm64" "$run_extra/tools/arm64/wiicompiled-setup" + copy_clean "$setup_x86_64" "$run_extra/tools/x86_64/wiicompiled-setup" + chmod +x "$run_extra/wiicompiled-setup" "$run_extra/tools/"*/wiicompiled-setup + codesign --force --sign - "$run_extra/tools/"*/wiicompiled-setup + sed "s/@VERSION@/$version/" "$script_dir/setup-run-header.sh" > "$stage/setup.run" + COPYFILE_DISABLE=1 /usr/bin/tar -czf - -C "$resources" . -C "$run_extra" . >> "$stage/setup.run" + chmod +x "$stage/setup.run" + ditto "$stage/setup.run" "$run_output" + printf 'Created self-extracting setup: %s\n' "$run_output" +fi pkg="$stage/WiiCompiled-Setup-unsigned.pkg" DITTONORSRC=1 COPYFILE_DISABLE=1 pkgbuild --root "$stage/root" --identifier org.wiicompiled.setup --version "$version" --install-location / "$pkg" if [[ -n "$identity" ]]; then productbuild --sign "$identity" --package "$pkg" "$output"; else ditto "$pkg" "$output"; fi diff --git a/Launcher/macos/setup-run-header.sh b/Launcher/macos/setup-run-header.sh new file mode 100644 index 000000000..1986f1bd4 --- /dev/null +++ b/Launcher/macos/setup-run-header.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# Header of WiiCompiled-Setup-macos.run, the self-extracting setup that frontends such as Wheel Wizard +# download like the Linux AppImage. build-setup-pkg.command fills in the version and appends the +# Setup.app Resources as a gzipped tar after the marker line. The bundle is unpacked once per version +# into Application Support, then its wiicompiled-setup entry point runs from there. +set -euo pipefail +version='@VERSION@' +if [[ $# -eq 1 && $1 == --version ]]; then printf '%s\n' "$version"; exit 0; fi + +setup_root="$HOME/Library/Application Support/WiiCompiled/Setup" +bundle="$setup_root/$version" +if [[ ! -x "$bundle/wiicompiled-setup" ]]; then + mkdir -p "$setup_root" + staging=$(mktemp -d "$setup_root/.unpack.XXXXXX") + trap 'rm -rf "$staging"' EXIT + payload_line=$(awk '/^__WIICOMPILED_PAYLOAD__$/ { print NR + 1; exit }' "$0") + tail -n +"$payload_line" "$0" | /usr/bin/tar -xzf - -C "$staging" \ + || { printf 'WiiCompiled setup: could not unpack %s; the download may be incomplete\n' "$0" >&2; exit 1; } + # Not safe against two first runs racing; frontends already run setup operations one at a time. + rm -rf "$bundle" + mv "$staging" "$bundle" + trap - EXIT + # Older versions are never run again once this one is unpacked. + find "$setup_root" -mindepth 1 -maxdepth 1 ! -name "$version" ! -name '.unpack.*' -exec rm -rf {} + +fi +exec "$bundle/wiicompiled-setup" "$@" +__WIICOMPILED_PAYLOAD__ diff --git a/Launcher/macos/setup.command b/Launcher/macos/setup.command index a839ad3d1..8ad706608 100755 --- a/Launcher/macos/setup.command +++ b/Launcher/macos/setup.command @@ -98,29 +98,7 @@ for tool in "$nodtool" "$translator" "$cmake_bin" "$ninja_bin"; do done mkdir -p "$support_root" "$products" -source_bundle_version="$workspace_source/.bundle-version" -workspace_bundle_version="$workspace/.bundle-version" -needs_workspace_refresh=0 -if [[ ! -f "$workspace/projects/mkwii/recomp.yml" ]]; then - needs_workspace_refresh=1 -elif [[ -f "$source_bundle_version" ]] && [[ ! -f "$workspace_bundle_version" || "$(<"$source_bundle_version")" != "$(<"$workspace_bundle_version")" ]]; then - needs_workspace_refresh=1 -fi - -if (( needs_workspace_refresh )); then - printf 'Preparing the local build workspace...\n' - if [[ ! -d "$workspace" ]]; then - /usr/bin/ditto "$workspace_source" "$workspace" - else - # Refresh only packaged source inputs. Assets and the staged Retro - # Rewind package belong to the user and stay in place; unchanged files - # keep their timestamps so the incremental native build survives. - # shellcheck source=../build-cache.sh - source "$workspace_source/Launcher/build-cache.sh" - mkw_sync_tree "$workspace_source" "$workspace" aurora-main projects runtime translator Launcher - /usr/bin/ditto "$source_bundle_version" "$workspace_bundle_version" - fi -fi +"$resources/sync-workspace.command" "$workspace_source" "$workspace" # The extracted disc decides the release, and with it the region's Retro-WFC payload. # shellcheck source=../build-cache.sh diff --git a/Launcher/macos/sync-workspace.command b/Launcher/macos/sync-workspace.command new file mode 100755 index 000000000..fba673825 --- /dev/null +++ b/Launcher/macos/sync-workspace.command @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +# Copies the packaged build workspace into a writable per-user location, or refreshes its source +# inputs when the package version changed. Shared by setup.command (Setup.pkg) and the +# wiicompiled-setup entry point (WiiCompiled-Setup-macos.run). +set -euo pipefail + +[[ $# -eq 2 ]] || { printf 'Usage: sync-workspace.command PACKAGED-WORKSPACE USER-WORKSPACE\n' >&2; exit 1; } +workspace_source=$1; workspace=$2 + +source_bundle_version="$workspace_source/.bundle-version" +workspace_bundle_version="$workspace/.bundle-version" +needs_workspace_refresh=0 +if [[ ! -f "$workspace/projects/mkwii/recomp.yml" ]]; then + needs_workspace_refresh=1 +elif [[ -f "$source_bundle_version" ]] && [[ ! -f "$workspace_bundle_version" || "$(<"$source_bundle_version")" != "$(<"$workspace_bundle_version")" ]]; then + needs_workspace_refresh=1 +fi + +if (( needs_workspace_refresh )); then + printf 'Preparing the local build workspace...\n' + if [[ ! -d "$workspace" ]]; then + /usr/bin/ditto "$workspace_source" "$workspace" + else + # Refresh only packaged source inputs. Assets and the staged Retro + # Rewind package belong to the user and stay in place; unchanged files + # keep their timestamps so the incremental native build survives. + # shellcheck source=../build-cache.sh + source "$workspace_source/Launcher/build-cache.sh" + mkw_sync_tree "$workspace_source" "$workspace" aurora-main projects runtime translator Launcher + /usr/bin/ditto "$source_bundle_version" "$workspace_bundle_version" + fi +fi diff --git a/Launcher/macos/wiicompiled-setup.command b/Launcher/macos/wiicompiled-setup.command new file mode 100755 index 000000000..3f6bb0303 --- /dev/null +++ b/Launcher/macos/wiicompiled-setup.command @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# Command-line entry point bundled in WiiCompiled-Setup-macos.run as wiicompiled-setup, for +# frontends such as Wheel Wizard. The macOS counterpart of the AppImage's AppRun: it runs the +# subcommand setup with the bundled tools, so nothing has to be on PATH. An app launched from +# Finder or the Dock only gets /usr/bin:/bin:/usr/sbin:/sbin. +set -euo pipefail + +resources=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +arch=$(uname -m) +case "$arch" in arm64|x86_64) ;; *) printf 'wiicompiled-setup: unsupported macOS architecture: %s\n' "$arch" >&2; exit 1 ;; esac +tools="$resources/tools/$arch" +# Shared with setup.command, so both entry points reuse one extraction and translation cache. +workspace="$HOME/Library/Application Support/WiiCompiled/BuildWorkspace" + +# Callers pass the subcommand first. Only install builds, so only it needs the compiler and a +# writable workspace; --version and launch-* stay fast. Output goes to stderr because +# --progress-json reserves stdout for its event stream. +if [[ "${1:-}" == install ]]; then + if ! /usr/bin/xcode-select -p >/dev/null 2>&1; then + /usr/bin/xcode-select --install >/dev/null 2>&1 || true + printf "wiicompiled-setup: Xcode Command Line Tools are required to compile WiiCompiled. Finish Apple's installer, then try again.\n" >&2 + exit 1 + fi + mkdir -p "$(dirname "$workspace")" + "$resources/sync-workspace.command" "$resources/workspace" "$workspace" >&2 +fi + +exec "$tools/wiicompiled-setup" --workspace "$workspace" \ + --translator-bin "$tools/Translator.Cli" --disc-tool-bin "$tools/nodtool" \ + --cmake "$resources/tools/cmake/bin/cmake" --ninja "$tools/ninja" "$@"