Add initial macOS build support #715

Closed
yeetbot90 wants to merge 35 commits from main into main
yeetbot90 commented 2026-11-08 18:30:01 +00:00 (Migrated from github.com)

macOS builder app

Adds an Apple Silicon macOS builder package that uses the existing Hookshot Builder interface. The generated HookshotBuilder.app launches the same Tk-based builder used by the Linux package, with macOS-specific config and Finder-folder handling. A command-line launcher is included as well.

The builder runs its x86-64 game toolchain under Rosetta 2 and uses WebGPU's Metal backend. CI packages Python, SDL2, static FFmpeg and wgpu-native with the source. It does not receive a game dump or build a game; users supply their own .nup file.

The first package attempt took about 15 minutes and failed after dependency compilation because the wgpu-native license URL used hyphens instead of the upstream filenames' periods. This update fixes those URLs, runs dependency builds natively on Apple Silicon (only the x86 Python runtime uses Rosetta), skips the separate dav1d build in favor of FFmpeg's AV1 decoder, and caches built dependencies. The macOS builder job compiles the app, checks the packaged launcher, and uploads `HookshotBuilder-macos-arm64"

Validation

  • 5 focused macOS build-path tests pass.
  • Python syntax, shell syntax, workflow YAML, and whitespace checks pass locally.
  • The new macOS workflow is pending; its dependency build, AppleScript app bundle, and artifact upload require the macOS runner. A full game build is intentionally not run without the user's dump.
## macOS builder app Adds an Apple Silicon macOS builder package that uses the existing Hookshot Builder interface. The generated `HookshotBuilder.app` launches the same Tk-based builder used by the Linux package, with macOS-specific config and Finder-folder handling. A command-line launcher is included as well. The builder runs its x86-64 game toolchain under Rosetta 2 and uses WebGPU's Metal backend. CI packages Python, SDL2, static FFmpeg and wgpu-native with the source. It does **not** receive a game dump or build a game; users supply their own `.nup` file. The first package attempt took about 15 minutes and failed after dependency compilation because the wgpu-native license URL used hyphens instead of the upstream filenames' periods. This update fixes those URLs, runs dependency builds natively on Apple Silicon (only the x86 Python runtime uses Rosetta), skips the separate dav1d build in favor of FFmpeg's AV1 decoder, and caches built dependencies. The macOS builder job compiles the app, checks the packaged launcher, and uploads `HookshotBuilder-macos-arm64" ## Validation - 5 focused macOS build-path tests pass. - Python syntax, shell syntax, workflow YAML, and whitespace checks pass locally. - The new macOS workflow is pending; its dependency build, AppleScript app bundle, and artifact upload require the macOS runner. A full game build is intentionally not run without the user's dump.
shayderrr commented 2026-11-08 18:32:26 +00:00 (Migrated from github.com)

Fix conflicts please,

Honestly, macos would be hard to implement considering the fact that macos has integrated graphics, not a gpu, meaning that the fps you would probably experience in game would be less then ideal.

What are you averaging in game on macOS?

Fix conflicts please, Honestly, macos would be hard to implement considering the fact that macos has integrated graphics, not a gpu, meaning that the fps you would probably experience in game would be less then ideal. What are you averaging in game on macOS?
yeetbot90 commented 2026-11-08 18:33:27 +00:00 (Migrated from github.com)

i am currently testing it so ii changed it to a drafft

i am currently testing it so ii changed it to a drafft
klimovich008 commented 2026-11-08 18:39:10 +00:00 (Migrated from github.com)

Looks cool, yet I'm curious why this is even needed in the first place. I believe there are projects like Macnative that have this done already.

Looks cool, yet I'm curious why this is even needed in the first place. I believe there are projects like Macnative that have this done already.
yeetbot90 commented 2026-11-08 18:43:49 +00:00 (Migrated from github.com)

As I thought it would be cool to just have a version of hookshot for mac as I believe it's great.

As I thought it would be cool to just have a version of hookshot for mac as I believe it's great.
yeetbot90 commented 2026-11-08 18:44:25 +00:00 (Migrated from github.com)

And I also have another Mac computer and I want to just try to port something to mac for once

And I also have another Mac computer and I want to just try to port something to mac for once
madebyjordan commented 2026-11-08 19:02:33 +00:00 (Migrated from github.com)

I have an M4 so would be happy to test this too

I have an M4 so would be happy to test this too
yeetbot90 commented 2026-11-08 19:03:54 +00:00 (Migrated from github.com)
https://github.com/NotRexed/Hookshot/actions/runs/42512541321/artifacts/13630345902 this should have the zip of the app
yeetbot90 commented 2026-11-08 19:04:56 +00:00 (Migrated from github.com)

tell me if somethings wrong as i haven't had the chance to test it yet as my laptop died and i am editing it from a pc

tell me if somethings wrong as i haven't had the chance to test it yet as my laptop died and i am editing it from a pc
gab9281 commented 2026-11-08 19:42:59 +00:00 (Migrated from github.com)

Could you check if it support sdl3 ? there's a new stub for swapping between 2 and 3. And could you check for cross-compilation from linux (most generic builder in CI's), its mostly a recommendation to be able to do 3 builds from the same type of machine

Could you check if it support sdl3 ? there's a new stub for swapping between 2 and 3. And could you check for cross-compilation from linux (most generic builder in CI's), its mostly a recommendation to be able to do 3 builds from the same type of machine
gab9281 commented 2026-11-08 19:44:56 +00:00 (Migrated from github.com)

Could you check to combine work on this ?
#459

Could you check to combine work on this ? https://git.magicbean.dev/MagicBeanDev/Hookshot/pulls/459
yeetbot90 commented 2026-11-08 19:45:34 +00:00 (Migrated from github.com)

I'll try

I'll try
yeetbot90 commented 2026-11-08 20:01:46 +00:00 (Migrated from github.com)

https://github.com/NotRexed/Hookshot/actions/runs/42517523284/artifacts/13632390784 The newest one if someone wants to try It should work and has the other ones in it too

https://github.com/NotRexed/Hookshot/actions/runs/42517523284/artifacts/13632390784 The newest one if someone wants to try It should work and has the other ones in it too
madebyjordan commented 2026-11-08 21:06:29 +00:00 (Migrated from github.com)

Tested the latest build (run 42517523284) on an M4 Pro, macOS 27.0.1, with Xcode installed. It didn't work as downloaded. I hit two bugs:

1. Reading the .nup fails with 'string.h' file not found

--check --nup ... fails while building zbic.dylib:

third_party/zbic/zstd.c:97:10: fatal error: 'string.h' file not found

nx2/zbic.py _build() calls Xcode's clang by its full path (.../XcodeDefault.xctoolchain/usr/bin/clang). It only passes native_target/native_link, not the macOS sysroot. Called directly like that, clang can't find the SDK headers. check_macos_toolchain() already passes toolchain.macos_sysroot_flags(), so the startup check passes and the failure only shows up later. A fix would be to add macos_sysroot_flags() to the zbic compile (and any other host compiles). Another option is to export SDKROOT="$(xcrun --show-sdk-path)" in HookshotBuilder.command and in the app's AppleScript launcher. I did the SDKROOT version locally and --check then passed: "This is the version Hookshot supports (build e0f3ccfa)."

2. HookshotBuilder.app has an invalid code signature

$ codesign --verify --deep --strict HookshotBuilder.app
HookshotBuilder.app: a sealed resource is missing or invalid
file added: .../Contents/Resources/tools/ffmpeg/include/libavutil/hwcontext.h
...

It looks like the app is ad-hoc signed before tools/ is copied into Contents/Resources. If someone downloads it in a browser, Gatekeeper will probably block it. Signing as the last packaging step should fix it (codesign --force --deep -s - HookshotBuilder.app).

With both fixed locally, the app opens to the builder window. I'll report back after a full build.

Tested the latest build (run 42517523284) on an M4 Pro, macOS 27.0.1, with Xcode installed. It didn't work as downloaded. I hit two bugs: **1. Reading the `.nup` fails with `'string.h' file not found`** `--check --nup ...` fails while building `zbic.dylib`: ``` third_party/zbic/zstd.c:97:10: fatal error: 'string.h' file not found ``` `nx2/zbic.py` `_build()` calls Xcode's clang by its full path (`.../XcodeDefault.xctoolchain/usr/bin/clang`). It only passes `native_target`/`native_link`, not the macOS sysroot. Called directly like that, clang can't find the SDK headers. `check_macos_toolchain()` already passes `toolchain.macos_sysroot_flags()`, so the startup check passes and the failure only shows up later. A fix would be to add `macos_sysroot_flags()` to the zbic compile (and any other host compiles). Another option is to export `SDKROOT="$(xcrun --show-sdk-path)"` in `HookshotBuilder.command` and in the app's AppleScript launcher. I did the `SDKROOT` version locally and `--check` then passed: "This is the version Hookshot supports (build e0f3ccfa)." **2. `HookshotBuilder.app` has an invalid code signature** ``` $ codesign --verify --deep --strict HookshotBuilder.app HookshotBuilder.app: a sealed resource is missing or invalid file added: .../Contents/Resources/tools/ffmpeg/include/libavutil/hwcontext.h ... ``` It looks like the app is ad-hoc signed before `tools/` is copied into `Contents/Resources`. If someone downloads it in a browser, Gatekeeper will probably block it. Signing as the last packaging step should fix it (`codesign --force --deep -s - HookshotBuilder.app`). With both fixed locally, the app opens to the builder window. I'll report back after a full build.
madebyjordan commented 2026-11-08 21:19:54 +00:00 (Migrated from github.com)

Update: after a few local fixes the build finishes, but the game crashes on startup.

Fixed locally (please add to the PR):

  1. nx2/build.py: the macOS link is missing the C++ standard library. Add -lc++ to macOS HOST_LIBS.
  2. host/posix/win32_posix.c: InitializeCriticalSection, SleepConditionVariableSRW and SleepConditionVariableCS exist only in the Linux (#else) branch. Add them to the __APPLE__ branch too. They only use pthreads, so the same code works.
  3. nx2/build.py: libwgpu_native.dylib is only copied into the game folder in the Windows branch. On macOS the game can't find it at launch.

Still broken:

  • Crash ~13s in: it crashes inside makecontext in CreateFiberEx (called from nn::os::InitializeFiber), writing just past the top of the fiber stack. macOS deprecates getcontext/makecontext, and they don't work reliably on Apple Silicon, so fibers probably need a different implementation on Mac.
  • No window: host/posix/display_sdl.c forces SDL's video driver to wayland,x11, so the game runs headless on macOS. Skip that hint on __APPLE__.
  • Minor: the save path comes out as ~/.local/share/hookshot\save\... (Linux path with backslashes).

Tested on an M4 Pro, macOS 27.0.1.

Update: after a few local fixes the build finishes, but the game crashes on startup. **Fixed locally (please add to the PR):** 1. `nx2/build.py`: the macOS link is missing the C++ standard library. Add `-lc++` to macOS `HOST_LIBS`. 2. `host/posix/win32_posix.c`: `InitializeCriticalSection`, `SleepConditionVariableSRW` and `SleepConditionVariableCS` exist only in the Linux (`#else`) branch. Add them to the `__APPLE__` branch too. They only use pthreads, so the same code works. 3. `nx2/build.py`: `libwgpu_native.dylib` is only copied into the game folder in the Windows branch. On macOS the game can't find it at launch. **Still broken:** - **Crash ~13s in:** it crashes inside `makecontext` in `CreateFiberEx` (called from `nn::os::InitializeFiber`), writing just past the top of the fiber stack. macOS deprecates `getcontext`/`makecontext`, and they don't work reliably on Apple Silicon, so fibers probably need a different implementation on Mac. - **No window:** `host/posix/display_sdl.c` forces SDL's video driver to `wayland,x11`, so the game runs headless on macOS. Skip that hint on `__APPLE__`. - **Minor:** the save path comes out as `~/.local/share/hookshot\save\...` (Linux path with backslashes). Tested on an M4 Pro, macOS 27.0.1.
madebyjordan commented 2026-11-08 21:49:15 +00:00 (Migrated from github.com)

Last update from me. I'm on Windows and only tested this on my Mac as a favour, so I'm handing it back to you. With the fixes below the game boots to the title screen on an M4 Pro at about 30 fps.

More fixes needed (on top of my last comment):

  1. Startup crash in CreateFiberEx (host/posix/win32_posix.c): macOS's makecontext zeroes the whole stack, so it hits the guard page that was just mprotected. On __APPLE__, add the guard after makecontext, sized getpagesize() (16 KB on Apple Silicon).
  2. No window (host/posix/display_sdl.c): skip the SDL_VIDEODRIVER=wayland,x11 hint on __APPLE__ so SDL uses cocoa.
  3. Black videos: scripts/macos/deps.sh dropped dav1d, but FFmpeg's built-in av1 decoder is hardware-only. Build dav1d like scripts/linux/deps.sh does and configure FFmpeg with --enable-libdav1d --enable-decoder=vp8,vp9,libdav1d. build.py already links libdav1d.a when it's in the prefix. I tested this with dav1d 1.5.4 + FFmpeg 9.0.2 and the movies decode.

Still broken (not fixed):

  • The title logo is drawn with one diagonal half missing, as if one triangle of a quad is dropped. RX_NO_CULL didn't obviously fix it. It would be worth comparing with Windows/Linux to see whether it only happens on Metal.
  • The window focus check sometimes reports "game window not in front (foreground window: process 0)", which might drop input.
  • Save path: ~/.local/share/hookshot\save\....

I didn't get past the title screen.

Last update from me. I'm on Windows and only tested this on my Mac as a favour, so I'm handing it back to you. With the fixes below the game boots to the title screen on an M4 Pro at about 30 fps. **More fixes needed (on top of my last comment):** 1. **Startup crash in `CreateFiberEx`** (`host/posix/win32_posix.c`): macOS's `makecontext` zeroes the whole stack, so it hits the guard page that was just `mprotect`ed. On `__APPLE__`, add the guard after `makecontext`, sized `getpagesize()` (16 KB on Apple Silicon). 2. **No window** (`host/posix/display_sdl.c`): skip the `SDL_VIDEODRIVER=wayland,x11` hint on `__APPLE__` so SDL uses cocoa. 3. **Black videos**: `scripts/macos/deps.sh` dropped dav1d, but FFmpeg's built-in `av1` decoder is hardware-only. Build dav1d like `scripts/linux/deps.sh` does and configure FFmpeg with `--enable-libdav1d --enable-decoder=vp8,vp9,libdav1d`. `build.py` already links `libdav1d.a` when it's in the prefix. I tested this with dav1d 1.5.4 + FFmpeg 9.0.2 and the movies decode. **Still broken (not fixed):** - The title logo is drawn with one diagonal half missing, as if one triangle of a quad is dropped. `RX_NO_CULL` didn't obviously fix it. It would be worth comparing with Windows/Linux to see whether it only happens on Metal. - The window focus check sometimes reports "game window not in front (foreground window: process 0)", which might drop input. - Save path: `~/.local/share/hookshot\save\...`. I didn't get past the title screen.
NotRexed commented 2026-11-09 05:30:09 +00:00 (Migrated from github.com)

Closing to keep the queue clear — please rebase on current main and reopen; thanks!

Closing to keep the queue clear — please rebase on current main and reopen; thanks!
yeetbot90 commented 2026-11-09 09:49:18 +00:00 (Migrated from github.com)

Ok Thanks for all the help I'll try to fix it just as you also said

Ok Thanks for all the help I'll try to fix it just as you also said
Commenting is not possible because the repository is archived.
No description provided.