mirror of
https://github.com/Zelda64Recomp/Zelda64Recomp
synced 2026-05-30 00:47:23 -04:00
Add macOS Support
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleName</key>
|
||||
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>Zelda64Recompiled</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.games</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>11</string>
|
||||
<key>GCSupportsGameMode</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,87 @@
|
||||
# Define the path to the entitlements file
|
||||
set(ENTITLEMENTS_FILE ${CMAKE_SOURCE_DIR}/.github/macos/entitlements.plist)
|
||||
|
||||
# Set bundle properties
|
||||
set_target_properties(Zelda64Recompiled PROPERTIES
|
||||
MACOSX_BUNDLE TRUE
|
||||
MACOSX_BUNDLE_BUNDLE_NAME "Zelda64Recompiled"
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER "com.github.zelda64recompiled"
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION "1.0"
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING "1.0"
|
||||
MACOSX_BUNDLE_ICON_FILE "AppIcon.icns"
|
||||
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_BINARY_DIR}/Info.plist
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-"
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS ${ENTITLEMENTS_FILE}
|
||||
)
|
||||
|
||||
# Create icon files for macOS bundle
|
||||
set(ICON_SOURCE ${CMAKE_SOURCE_DIR}/icons/512.png)
|
||||
set(ICONSET_DIR ${CMAKE_BINARY_DIR}/AppIcon.iconset)
|
||||
set(ICNS_FILE ${CMAKE_BINARY_DIR}/resources/AppIcon.icns)
|
||||
|
||||
# Create iconset directory and add PNG file
|
||||
add_custom_command(
|
||||
OUTPUT ${ICONSET_DIR}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${ICONSET_DIR}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${ICON_SOURCE} ${ICONSET_DIR}/icon_512x512.png
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${ICON_SOURCE} ${ICONSET_DIR}/icon_512x512@2x.png
|
||||
COMMAND touch ${ICONSET_DIR}
|
||||
COMMENT "Creating iconset directory and copying PNG file"
|
||||
)
|
||||
|
||||
# Convert iconset to icns
|
||||
add_custom_command(
|
||||
OUTPUT ${ICNS_FILE}
|
||||
DEPENDS ${ICONSET_DIR}
|
||||
COMMAND iconutil -c icns ${ICONSET_DIR} -o ${ICNS_FILE}
|
||||
COMMENT "Converting iconset to icns"
|
||||
)
|
||||
|
||||
# Custom target to ensure icns creation
|
||||
add_custom_target(create_icns ALL DEPENDS ${ICNS_FILE})
|
||||
|
||||
# Set source file properties for the resulting icns file
|
||||
set_source_files_properties(${ICNS_FILE} PROPERTIES
|
||||
MACOSX_PACKAGE_LOCATION "Resources"
|
||||
)
|
||||
|
||||
# Add the icns file to the executable target
|
||||
target_sources(Zelda64Recompiled PRIVATE ${ICNS_FILE})
|
||||
|
||||
# Ensure Zelda64Recompiled depends on create_icns
|
||||
add_dependencies(Zelda64Recompiled create_icns)
|
||||
|
||||
# Configure Info.plist
|
||||
configure_file(${CMAKE_SOURCE_DIR}/.github/macos/Info.plist.in ${CMAKE_BINARY_DIR}/Info.plist @ONLY)
|
||||
|
||||
# Install the app bundle
|
||||
install(TARGETS Zelda64Recompiled BUNDLE DESTINATION .)
|
||||
|
||||
# Ensure the entitlements file exists
|
||||
if(NOT EXISTS ${ENTITLEMENTS_FILE})
|
||||
message(FATAL_ERROR "Entitlements file not found at ${ENTITLEMENTS_FILE}")
|
||||
endif()
|
||||
|
||||
# Post-build steps for macOS bundle
|
||||
add_custom_command(TARGET Zelda64Recompiled POST_BUILD
|
||||
# Copy and fix frameworks first
|
||||
COMMAND ${CMAKE_COMMAND} -D CMAKE_BUILD_TYPE=$<CONFIG> -D CMAKE_GENERATOR=${CMAKE_GENERATOR} -P ${CMAKE_SOURCE_DIR}/.github/macos/fixup_bundle.cmake
|
||||
|
||||
# Copy all resources
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/assets ${CMAKE_BINARY_DIR}/temp_assets
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/temp_assets/scss
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/temp_assets $<TARGET_BUNDLE_DIR:Zelda64Recompiled>/Contents/Resources/assets
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/temp_assets
|
||||
|
||||
# Copy controller database
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/gamecontrollerdb.txt $<TARGET_BUNDLE_DIR:Zelda64Recompiled>/Contents/Resources/
|
||||
|
||||
# Set RPATH
|
||||
COMMAND install_name_tool -add_rpath "@executable_path/../Frameworks/" $<TARGET_BUNDLE_DIR:Zelda64Recompiled>/Contents/MacOS/Zelda64Recompiled
|
||||
|
||||
# Sign the bundle
|
||||
COMMAND codesign --verbose=4 --options=runtime --no-strict --sign - --entitlements ${ENTITLEMENTS_FILE} --deep --force $<TARGET_BUNDLE_DIR:Zelda64Recompiled>
|
||||
|
||||
COMMENT "Performing post-build steps for macOS bundle"
|
||||
VERBATIM
|
||||
)
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-executable-page-protection</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,44 @@
|
||||
include(BundleUtilities)
|
||||
|
||||
# Check for pkgx installation
|
||||
find_program(PKGX_EXECUTABLE pkgx)
|
||||
|
||||
# Xcode generator puts the build type in the build directory
|
||||
set(BUILD_PREFIX "")
|
||||
if (CMAKE_GENERATOR STREQUAL "Xcode")
|
||||
set(BUILD_PREFIX "${CMAKE_BUILD_TYPE}/")
|
||||
endif()
|
||||
|
||||
# Use generator expressions to get the absolute path to the bundle
|
||||
set(APPS "${BUILD_PREFIX}Zelda64Recompiled.app/Contents/MacOS/Zelda64Recompiled")
|
||||
|
||||
# Set up framework search paths
|
||||
set(DIRS "${BUILD_PREFIX}Zelda64Recompiled.app/Contents/Frameworks")
|
||||
|
||||
# Detect if we're using pkgx
|
||||
if(PKGX_EXECUTABLE)
|
||||
message(STATUS "pkgx detected, adding pkgx directories to framework search path")
|
||||
list(APPEND DIRS "$ENV{HOME}/.pkgx/")
|
||||
endif()
|
||||
|
||||
# Convert all paths to absolute paths
|
||||
file(REAL_PATH ${APPS} APPS)
|
||||
|
||||
set(RESOLVED_DIRS "")
|
||||
foreach(DIR IN LISTS DIRS)
|
||||
# Handle home directory expansion
|
||||
string(REPLACE "~" "$ENV{HOME}" DIR "${DIR}")
|
||||
# Convert to absolute path, but don't fail if directory doesn't exist
|
||||
if(EXISTS "${DIR}")
|
||||
file(REAL_PATH "${DIR}" RESOLVED_DIR)
|
||||
list(APPEND RESOLVED_DIRS "${RESOLVED_DIR}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Debug output
|
||||
message(STATUS "Bundle fixup paths:")
|
||||
message(STATUS " App: ${APPS}")
|
||||
message(STATUS " Search dirs: ${RESOLVED_DIRS}")
|
||||
|
||||
# Fix up the bundle
|
||||
fixup_bundle("${APPS}" "" "${RESOLVED_DIRS}")
|
||||
Executable
+73
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/python3
|
||||
"""
|
||||
Custom ld64 wrapper for macOS
|
||||
|
||||
This script wraps the standard macOS linker (/usr/bin/ld) to modify executable memory
|
||||
protection flags in the resulting Mach-O binary. It works in three stages:
|
||||
|
||||
1. First, it passes through all arguments to the regular macOS linker to create the binary
|
||||
2. Then, it parses command line arguments to identify output file and segment protection flags
|
||||
3. Finally, it modifies the output binary's Mach-O headers to ensure segments (particularly __TEXT)
|
||||
have the maximum protection flags (rwx) we specify, even if the default macOS linker would restrict them
|
||||
|
||||
This is necessary because macOS restricts writable+executable memory by default,
|
||||
but certain applications need this capability for dynamic code generation or JIT compilation.
|
||||
|
||||
Usage: Same as the standard ld64 linker, with the added benefit that -segprot options
|
||||
will have their max_prot values properly preserved in the output binary.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import subprocess
|
||||
from itertools import takewhile
|
||||
from macholib import MachO, ptypes
|
||||
|
||||
def parse_rwx(text):
|
||||
return ('r' in text and 1) | ('w' in text and 2) | ('x' in text and 4)
|
||||
|
||||
def apply_maxprots(path, maxprots):
|
||||
mach = MachO.MachO(path)
|
||||
header = mach.headers[0]
|
||||
offset = ptypes.sizeof(header.mach_header)
|
||||
|
||||
for cload, ccmd, cdata in header.commands:
|
||||
if not hasattr(ccmd, 'segname'):
|
||||
break
|
||||
|
||||
if hasattr(ccmd.segname, 'to_str'):
|
||||
segname = ccmd.segname.to_str().decode('utf-8').strip('\0')
|
||||
else:
|
||||
segname = ccmd.segname.decode('utf-8').strip('\0')
|
||||
|
||||
if segname in maxprots and ccmd.maxprot != maxprots[segname]:
|
||||
fields = list(takewhile(lambda field: field[0] != 'maxprot', cload._fields_ + ccmd._fields_))
|
||||
index = offset + sum(ptypes.sizeof(typ) for _, typ in fields)
|
||||
|
||||
with open(path, 'r+b') as fh:
|
||||
fh.seek(index)
|
||||
fh.write(bytes([maxprots[segname]]))
|
||||
|
||||
offset += cload.cmdsize
|
||||
|
||||
try:
|
||||
subprocess.check_call(['/usr/bin/ld'] + sys.argv[1:])
|
||||
except subprocess.CalledProcessError as ex:
|
||||
sys.exit(ex.returncode)
|
||||
|
||||
output_file = 'a.out'
|
||||
segprots = {'__TEXT': parse_rwx('rwx')} # maxprot = rwx
|
||||
|
||||
i = 1
|
||||
while i < len(sys.argv):
|
||||
if sys.argv[i] == '-o' and i + 1 < len(sys.argv):
|
||||
output_file = sys.argv[i + 1]
|
||||
i += 2
|
||||
elif sys.argv[i] == '-segprot' and i + 3 < len(sys.argv):
|
||||
segment = sys.argv[i + 1]
|
||||
maxprot = sys.argv[i + 2]
|
||||
segprots[segment] = parse_rwx(maxprot)
|
||||
i += 4
|
||||
else:
|
||||
i += 1
|
||||
|
||||
apply_maxprots(output_file, segprots)
|
||||
@@ -0,0 +1,14 @@
|
||||
version: '2.9.3'
|
||||
prefix: '/opt/local'
|
||||
variants:
|
||||
select:
|
||||
- aqua
|
||||
- metal
|
||||
deselect: x11
|
||||
ports:
|
||||
- name: clang-18
|
||||
- name: llvm-18
|
||||
- name: libsdl2
|
||||
select: universal
|
||||
- name: freetype
|
||||
select: universal
|
||||
@@ -78,16 +78,16 @@ jobs:
|
||||
- name: Hotpatch DXC into RT64's contrib
|
||||
run: |
|
||||
# check if dxc was updated before we replace it, to detect changes
|
||||
echo ${{ inputs.DXC_CHECKSUM }} ./lib/rt64/src/contrib/dxc/bin/x64/dxc | sha256sum --status -c -
|
||||
echo ${{ inputs.DXC_CHECKSUM }} ./lib/rt64/src/contrib/dxc/bin/x64/dxc-linux | sha256sum --status -c -
|
||||
|
||||
cp -v /usr/local/lib/libdxcompiler.so ./lib/rt64/src/contrib/dxc/lib/x64/libdxcompiler.so
|
||||
cp -v /usr/local/bin/dxc ./lib/rt64/src/contrib/dxc/bin/x64/dxc
|
||||
cp -v /usr/local/bin/dxc ./lib/rt64/src/contrib/dxc/bin/x64/dxc-linux
|
||||
- name: Build ZeldaRecomp
|
||||
run: |-
|
||||
# enable ccache
|
||||
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
|
||||
|
||||
cmake -DCMAKE_BUILD_TYPE=${{ matrix.type }} -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER=clang++-17 -DCMAKE_C_COMPILER=clang-17 -DCMAKE_MAKE_PROGRAM=ninja -G Ninja -S . -B cmake-build -DPATCHES_C_COMPILER=clang-17 -DPATCHES_LD=ld.lld-17 -DPATCHES_OBJCOPY=llvm-objcopy-17
|
||||
cmake -DCMAKE_BUILD_TYPE=${{ matrix.type }} -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER=clang++-17 -DCMAKE_C_COMPILER=clang-17 -DCMAKE_MAKE_PROGRAM=ninja -G Ninja -S . -B cmake-build -DPATCHES_C_COMPILER=clang-17 -DPATCHES_LD=ld.lld-17
|
||||
cmake --build cmake-build --config ${{ matrix.type }} --target Zelda64Recompiled -j $(nproc)
|
||||
- name: Prepare Archive
|
||||
run: |
|
||||
@@ -283,3 +283,74 @@ jobs:
|
||||
name: Zelda64Recompiled-PDB-${{ matrix.type }}
|
||||
path: |
|
||||
Zelda64Recompiled.pdb
|
||||
build-macos:
|
||||
runs-on: blaze/macos-14
|
||||
strategy:
|
||||
matrix:
|
||||
type: [ Debug, Release ]
|
||||
name: macos (x64, arm64, ${{ matrix.type }})
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha || github.ref }}
|
||||
submodules: recursive
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
key: ${{ runner.os }}-z64re-ccache-${{ matrix.type }}
|
||||
- name: Homebrew Setup
|
||||
run: |
|
||||
brew install ninja
|
||||
brew uninstall --ignore-dependencies libpng freetype
|
||||
- name: MacPorts Setup
|
||||
uses: melusina-org/setup-macports@v1
|
||||
id: 'macports'
|
||||
with:
|
||||
parameters: '.github/macos/macports.yaml'
|
||||
- name: Prepare Build
|
||||
run: |-
|
||||
git clone ${{ secrets.ZRE_REPO_WITH_PAT }}
|
||||
./zre/process.sh
|
||||
cp ./zre/mm_shader_cache.bin ./shadercache/
|
||||
- name: Build N64Recomp & RSPRecomp
|
||||
run: |
|
||||
git clone https://github.com/Mr-Wiseguy/N64Recomp.git --recurse-submodules N64RecompSource
|
||||
cd N64RecompSource
|
||||
git checkout ${{ inputs.N64RECOMP_COMMIT }}
|
||||
git submodule update --init --recursive
|
||||
|
||||
# enable ccache
|
||||
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
|
||||
|
||||
# Build N64Recomp & RSPRecomp
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_MAKE_PROGRAM=ninja -G Ninja -S . -B cmake-build
|
||||
cmake --build cmake-build --config Release --target N64Recomp -j $(sysctl -n hw.ncpu)
|
||||
cmake --build cmake-build --config Release --target RSPRecomp -j $(sysctl -n hw.ncpu)
|
||||
|
||||
# Copy N64Recomp & RSPRecomp to root directory
|
||||
cp cmake-build/N64Recomp ..
|
||||
cp cmake-build/RSPRecomp ..
|
||||
- name: Run N64Recomp & RSPRecomp
|
||||
run: |
|
||||
./N64Recomp us.rev1.toml
|
||||
./RSPRecomp aspMain.us.rev1.toml
|
||||
./RSPRecomp njpgdspMain.us.rev1.toml
|
||||
- name: Build ZeldaRecomp
|
||||
run: |-
|
||||
# enable ccache
|
||||
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
|
||||
|
||||
cmake -DCMAKE_BUILD_TYPE=${{ matrix.type }} -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_MAKE_PROGRAM=ninja -G Ninja -S . -B cmake-build \
|
||||
-DPATCHES_LD=/opt/local/bin/ld.lld-mp-18 -DCMAKE_AR=/opt/local/bin/llvm-ar-mp-18 -DPATCHES_C_COMPILER=/opt/local/bin/clang-mp-18 \
|
||||
-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"
|
||||
cmake --build cmake-build --config ${{ matrix.type }} --target Zelda64Recompiled -j $(sysctl -n hw.ncpu)
|
||||
- name: Prepare Archive
|
||||
run: |
|
||||
mv cmake-build/Zelda64Recompiled.app Zelda64Recompiled.app
|
||||
zip -r -y Zelda64Recompiled.zip Zelda64Recompiled.app
|
||||
- name: Archive Zelda64Recomp
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Zelda64Recompiled-${{ runner.os }}-${{ matrix.type }}
|
||||
path: Zelda64Recompiled.zip
|
||||
|
||||
Reference in New Issue
Block a user