Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion .github/workflows/package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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: |
Expand Down Expand Up @@ -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
Expand All @@ -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:
Expand All @@ -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<semver>, carrying the expected platform assets,
Expand Down Expand Up @@ -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")
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Code.pul
/build/
/build-*/
/native-build/
/native-build-macos/
/native-build-macos*/
/local-products/
/dist/
/out/
Expand Down
9 changes: 9 additions & 0 deletions Launcher/WiiCompiled.Setup.Common/NodToolProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
9 changes: 6 additions & 3 deletions Launcher/WiiCompiled.Setup.Linux/BuildRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Comment thread
coderabbitai[bot] marked this conversation as resolved.
if (!File.Exists(script)) throw new FileNotFoundException($"{Path.GetFileName(script)} is missing", script);

var startInfo = new ProcessStartInfo("bash")
{
Expand Down Expand Up @@ -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.");
}
}

Expand Down
2 changes: 2 additions & 0 deletions Launcher/WiiCompiled.Setup.Linux/DesktopEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion Launcher/WiiCompiled.Setup.Linux/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<RootNamespace>WiiCompiled.Setup.Linux</RootNamespace>
<Authors>patchzy</Authors>
<Product>WiiCompiled</Product>
<Description>Command-line installer and launcher for WiiCompiled on Linux</Description>
<Description>Command-line installer and launcher for WiiCompiled on Linux and macOS</Description>
<DebugType>embedded</DebugType>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
<InvariantGlobalization>true</InvariantGlobalization>
Expand Down
20 changes: 18 additions & 2 deletions Launcher/local-build-macos.command
Original file line number Diff line number Diff line change
Expand Up @@ -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" <<JSON
{
"SchemaVersion": 1,
"Profile": "$2",
"BuiltUtc": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"DolSha256": "$(mkw_sha256 "$assets/main.dol")",
"RelSha256": "$(mkw_sha256 "$assets/StaticR.rel")",
"CodePulSha256": $code_pul_sha,
"Compiler": "$(clang++ --version | head -1)"
}
JSON
}
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"; write_build_record "${base_output_dir:-$output_dir}" base; 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"; write_build_record "$output_dir" retro-rewind; fi
printf 'MKWCBUILD:OUTPUT=%s\n' "$output_dir"
35 changes: 30 additions & 5 deletions Launcher/macos/build-setup-pkg.command
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ fail() { printf 'build-setup-pkg.command: error: %s\n' "$*" >&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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -59,14 +63,15 @@ 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
lipo "$artifact" -verify_arch "$arch" >/dev/null 2>&1 || fail "$label must contain a $arch slice: $artifact"
}
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'

Expand All @@ -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
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
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
Expand Down
27 changes: 27 additions & 0 deletions Launcher/macos/setup-run-header.sh
Original file line number Diff line number Diff line change
@@ -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__
24 changes: 1 addition & 23 deletions Launcher/macos/setup.command
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading
Loading