mirror of
https://github.com/Zelda64Recomp/Zelda64Recomp
synced 2026-06-12 21:45:37 -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
|
||||
Reference in New Issue
Block a user