Experimental macOS (x86_64) port -- Mono + XQuartz, unlocks waterbox (DS) on macOS#4785
Open
DarthMDev wants to merge 10 commits into
Open
Experimental macOS (x86_64) port -- Mono + XQuartz, unlocks waterbox (DS) on macOS#4785DarthMDev wants to merge 10 commits into
DarthMDev wants to merge 10 commits into
Conversation
Port the waterbox host to build and run on macOS x86_64 (natively on Intel, under Rosetta 2 on Apple silicon). All `cargo test --target x86_64-apple-darwin` pass and melonDS boots and runs. - memory_block/pal.rs: use an unlinked temp file (mkstemp) instead of memfd_create/shm for the block handle. macOS forbids mprotect-ing a MAP_SHARED shm region executable (EACCES), but a regular file maps executable like a dylib, so the existing mirror/W^X model works unchanged. Also handle the macOS errno location (__error) and that MAP_FIXED_NOREPLACE is Linux-only. - memory_block/tripguard.rs: also hook SIGBUS (macOS raises SIGBUS, not SIGSEGV, for protection violations on mapped memory) and read the faulting access type from the macOS mcontext (__es.__err); drop the Linux-only sa_restorer field. - context/interop_macos.s (+ generated interop_macos.bin), context/mod.rs: macOS can't repoint the %gs base (no arch_prctl; rdgsbase/wrgsbase #UD under Rosetta) and %gs is the OS TSD. The guest only reads its Context ptr from gs:0x18; the macOS trampoline leaves gs:0x08/0x10 (errno/mig_reply) alone and swaps only gs:0x18 against a free TSD slot at each host/guest boundary. - host.rs, threading.rs: wrap std::intrinsics::breakpoint in unsafe (newer nightly). - build-release-macos.sh: cross-build the dylib (pinned nightly, low deployment target).
OS-gated changes so EmuHawk runs under Mono on macOS; no behavioural change on
Windows/Linux.
- OSTailoredCode: add DllExtension (".dll"/".dylib"/".so"); WaterboxHost uses it
to load libwaterboxhost.dylib on macOS.
- MemoryBlockLinuxPal: MAP_ANON is 0x20 on Linux/BSD but 0x1000 on macOS; pick
the right flag (the previous hardcoded 0x22 made mmap fail on macOS).
- SDL2OpenGLContext: still force the x11 video driver on macOS (Mono WinForms is
X11/XQuartz), but don't force EGL there — XQuartz provides GLX, not EGL.
- OpenGLProvider: report no host OpenGL on macOS. XQuartz's GL is the legacy
Apple GLX bridge (capped at 2.1, aborts under Rosetta); probing it crashes, so
cores (melonDS, N64, ...) fall back to their software renderers.
- Assets/EmuHawkMonoMacOS.sh: launcher for macOS. Runs the x86_64 Mono directly (NOT via `arch`, which is SIP-protected and strips DYLD_*), forces the X11 WinForms driver (MONO_MWF_MAC_FORCE_X11) and GdiPlus video (--gdi), and sets up DYLD paths incl. /opt/X11/lib for XQuartz. - Dist/stage-macos-dylibs.sh: symlink the Homebrew-provided deps and the Linux-soname aliases (libX11.so.6, etc.) into output/dll, all pointing at one consistent Homebrew libX11. - README: add an experimental macOS (x86_64) section with Intel + Apple silicon setup and a clear "not officially supported, don't file issues unless reproducible on Win/Linux" warning for maintainers. - .gitignore: ignore the Mono launcher's captured stdout/stderr logs.
YoshiRulz
reviewed
Jun 25, 2026
- Merge EmuHawkMonoMacOS.sh into EmuHawkMono.sh via a `uname` case branch; use PATH for Mono (respects e.g. a Nix install) instead of a hardcoded path. - Centralise the [DllImport]-style native library naming in DynamicLibraryImportResolver.PlatformFileName(); drop OSTailoredCode.DllExtension and use it from WaterboxHost. - SDL2OpenGLContext: split the macOS branch out from the generic Unix one. - MemoryBlockLinuxPal: hoist MAP_PRIVATE/MAP_ANON to named consts. - X11KeyMouseInput: drop the OS check (XOpenDisplay fails cleanly elsewhere; X11 works under XQuartz on macOS). - Revert the .gitignore entries (those logs only appear if run from Assets/).
Author
|
Do we also want to wait for #4784 to be merged? And see how that plays out before this is merged? |
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
…FileName
- Dist/.BuildInConfigX.sh: on macOS, run stage-macos-dylibs.sh after the build, since
the build overwrites output/dll and doesn't create the native-library symlinks.
- Dist/.InvokeCLIOnMainSln.sh: read MainVersion with sed instead of `grep -Po`, which is
GNU-only and absent on macOS/BSD.
- Encore: resolve the core via DynamicLibraryImportResolver.PlatformFileName("encore").
Hopefully fixing CI build
XQuartz's OpenGL is Apple's legacy GLX bridge (capped at GL 2.1 and crashes under Rosetta), so default DispMethod to the GdiPlus software renderer on macOS instead of OpenGL. Avoids needing to force --gdi at launch.
The Homebrew/XQuartz deps and the Linux-soname aliases (libX11.so.6, etc.) BizHawk's P/Invokes and Mono expect can't be shipped as symlinks (they point at the user's Homebrew install), so create them in ./dll on each launch instead, like the NixOS launch script. Doing it in the launcher also means they survive a rebuild overwriting output/dll. - Assets/EmuHawkMono.sh: add the symlink setup to the macOS branch; drop the --gdi force (the display method now defaults to GdiPlus on macOS in Config.cs). - Remove Dist/stage-macos-dylibs.sh and the macOS post-build step in Dist/.BuildInConfigX.sh (Package.sh runs in CI and can't make user-specific symlinks). - README: update the macOS deps (X11 client libs) and launch instructions.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Draft / RFC — experimental, not asking for a support commitment.
Revives a macOS port by running the existing x86_64 build under Mono + XQuartz
(natively on Intel, via Rosetta 2 on Apple silicon). Verified working: EmuHawk GUI,
Lua, GB/GBC (Gambatte), GBA (mGBA), and Nintendo DS (melonDS) — Pokémon
SoulSilver boots and runs at full speed from a real save. All changes are OS-gated; no
behavioural change on Windows/Linux.
Highlights
executable; SIGBUS handling for dirty-detection; a macOS
%gs/TSD trampoline(
interop_macos.s) since the GS base can't be repointed under Rosetta. All 26cargo test --target x86_64-apple-darwinpass.OSTailoredCode.DllExtension,MemoryBlockMAP_ANON fix, SDL2 GLX-not-EGL onmacOS, and host-GL reported unavailable (XQuartz GL is broken/2.1) so cores fall back to
software rendering.
EmuHawkMonoMacOS.shlauncher,Dist/stage-macos-dylibs.sh,build-release-macos.sh,and a README section with setup + an experimental/maintainer warning.
Scope/limitations: source-only (native dylibs are build artifacts; build with the
included scripts + Homebrew). Software (GdiPlus) video only -- no hardware GL / HD
upscaling. Requires macOS 14+ (Homebrew dep floor).
Refs #1430, #3697, #4052. Discussion: DarthMDev#1