Apple M1: Build, Analytics, and Memory Management

Analytics:
- Incorporated fix to allow the full set of analytics that was recommended by
  spotlightishere

BuildMacOSUniversalBinary:
- The x86_64 slice for a universal binary is now built for 10.12
- The universal binary build script now can be configured though command line
  options instead of modifying the script itself.
- os.system calls were replaced with equivalent subprocess calls
- Formatting was reworked to be more PEP 8 compliant
- The script was refactored to make it more modular
- The com.apple.security.cs.disable-library-validation entitlement was removed

Memory Management:
- Changed the JITPageWrite*Execute*() functions to incorporate support for
  nesting

Other:
- Fixed several small lint errors
- Fixed doc and formatting mistakes
- Several small refactors to make things clearer
This commit is contained in:
Skyler Saleh 2021-01-16 20:31:48 -08:00
parent 4ecb3084b7
commit 948764d37b
12 changed files with 406 additions and 180 deletions

View File

@ -1,146 +0,0 @@
"""
The current tooling supported in CMake, Homebrew, and QT5 are insufficient for creating
MacOSX universal binaries automatically for applications like Dolphin which have more
complicated build requirements (like different libraries, build flags and source files
for each target architecture).
So instead, this script manages the conifiguration and compilation of distinct builds
and project files for each target architecture and then merges the two binaries into
a single universal binary.
Running this script will:
1) Generate Xcode project files for the ARM build (if project files don't already exist)
2) Generate Xcode project files for the x64 build (if project files don't already exist)
3) Build the ARM project for the selected build_target
4) Build the x64 project for the selected build_target
5) Generates universal .app packages combining the ARM and x64 packages
6) Utilizes the lipo tool to combine the binary objects inside each of the packages
into universal binaries
7) Code signs the final universal binaries using the specified codesign_identity
"""
##BEGIN CONFIG##
#Location of destination universal binary
dst_app = "universal/"
#Build Target (dolphin-emu to just build the emulator and skip the tests)
build_target = "ALL_BUILD"
#Locations to pkg config files for arm and x64 libraries
#The default values of these paths are taken from the default
#paths used for homebrew
arm_pkg_config_path='/opt/homebrew/lib/pkgconfig'
x64_pkg_config_path='/usr/local/lib/pkgconfig'
#Locations to qt5 directories for arm and x64 libraries
#The default values of these paths are taken from the default
#paths used for homebrew
arm_qt5_path='/opt/homebrew/opt/qt5'
x64_qt5_path='/usr/local/opt/qt5'
# Identity to use for code signing. "-" indicates that the app will not
# be cryptographically signed/notarized but will instead just use a
# SHA checksum to verify the integrity of the app. This doesn't
# protect against malicious actors, but it does protect against
# running corrupted binaries and allows for access to the extended
# permisions needed for ARM builds
codesign_identity ='"-"'
##END CONFIG##
import glob
import sys
import os
import shutil
import filecmp
#Configure ARM project files if they don't exist
if not os.path.exists("arm"):
os.mkdir("arm");
os.chdir("arm");
os.system('PKG_CONFIG_PATH="'+arm_pkg_config_path+'" Qt5_DIR="'+arm_qt5_path+'" CMAKE_OSX_ARCHITECTURES=arm64 arch -arm64 cmake ../../ -G Xcode');
os.chdir("..");
#Configure x64 project files if they don't exist
if not os.path.exists("x64"):
os.mkdir("x64");
os.chdir("x64");
os.system('PKG_CONFIG_PATH="'+x64_pkg_config_path+'" Qt5_DIR="'+x64_qt5_path+'" CMAKE_OSX_ARCHITECTURES=x86_64 arch -x86_64 cmake ../../ -G Xcode')
os.chdir("..");
#Build ARM and x64 projects
os.system('xcodebuild -project arm/dolphin-emu.xcodeproj -target "'+build_target+'" -configuration Release');
os.system('xcodebuild -project x64/dolphin-emu.xcodeproj -target "'+build_target+'" -configuration Release');
#Merge ARM and x64 binaries into universal binaries
#Source binaries to merge together
src_app0 = "arm/Binaries/release"
src_app1 = "x64/Binaries/release"
if os.path.exists(dst_app): shutil.rmtree(dst_app)
os.mkdir(dst_app);
def lipo(path0,path1,dst):
cmd = 'lipo -create -output "'+dst + '" "' + path0 +'" "' + path1+'"'
print(cmd)
os.system(cmd)
def recursiveMergeBinaries(src0,src1,dst):
#loop over all files in src0
for newpath0 in glob.glob(src0+"/*"):
filename = os.path.basename(newpath0);
newpath1 = os.path.join(src1,filename);
new_dst_path = os.path.join(dst,filename);
if not os.path.islink(newpath0):
if os.path.exists(newpath1):
if os.path.isdir(newpath1):
os.mkdir(new_dst_path);
#recurse into directories
recursiveMergeBinaries(newpath0,newpath1,new_dst_path)
else:
if filecmp.cmp(newpath0,newpath1):
#copy files that are the same
shutil.copy(newpath0,new_dst_path);
else:
#lipo together files that are different
lipo(newpath0,newpath1,new_dst_path)
else:
#copy files that don't exist in path1
shutil.copy(newpath0,new_dst_path)
#loop over files in src1 and copy missing things over to dst
for newpath1 in glob.glob(src1+"/*"):
filename = os.path.basename(newpath0);
newpath0 = os.path.join(src0,filename);
new_dst_path = os.path.join(dst,filename);
if not os.path.exists(newpath0) and not os.path.islink(newpath1):
shutil.copytree(newpath1,new_dst_path);
#fix up symlinks for path0
for newpath0 in glob.glob(src0+"/*"):
filename = os.path.basename(newpath0);
new_dst_path = os.path.join(dst,filename);
if os.path.islink(newpath0):
relative_path = os.path.relpath(os.path.realpath(newpath0),src0)
print(relative_path,new_dst_path)
os.symlink(relative_path,new_dst_path);
#fix up symlinks for path1
for newpath1 in glob.glob(src1+"/*"):
filename = os.path.basename(newpath1);
new_dst_path = os.path.join(dst,filename);
newpath0 = os.path.join(src0,filename);
if os.path.islink(newpath1) and not os.path.exists(newpath0):
relative_path = os.path.relpath(os.path.realpath(newpath1),src1)
print(relative_path,new_dst_path)
os.symlink(relative_path,new_dst_path);
return;
#create univeral binary
recursiveMergeBinaries(src_app0,src_app1,dst_app);
#codesign
os.system("codesign --deep --force -s "+codesign_identity+" " +dst_app +"/*");

278
BuildMacOSUniversalBinary.py Executable file
View File

@ -0,0 +1,278 @@
#!/usr/bin/env python3
"""
The current tooling supported in CMake, Homebrew, and QT5 are insufficient for
creating macOS universal binaries automatically for applications like Dolphin
which have more complicated build requirements (like different libraries, build
flags and source files for each target architecture).
So instead, this script manages the configuration and compilation of distinct
builds and project files for each target architecture and then merges the two
binaries into a single universal binary.
Running this script will:
1) Generate Xcode project files for the ARM build (if project files don't
already exist)
2) Generate Xcode project files for the x64 build (if project files don't
already exist)
3) Build the ARM project for the selected build_target
4) Build the x64 project for the selected build_target
5) Generates universal .app packages combining the ARM and x64 packages
6) Utilizes the lipo tool to combine the binary objects inside each of the
packages into universal binaries
7) Code signs the final universal binaries using the specified
codesign_identity
"""
import argparse
import copy
import filecmp
import glob
import json # Used to print config
import os
import shutil
import subprocess
import sys
# #BEGIN CONFIG# #
# The config variables listed below are the defaults, but they can be
# overridden by command line arguments see parse_args(), or run:
# BuildMacOSUniversalBinary.py --help
DEFAULT_CONFIG = {
# Location of destination universal binary
"dst_app": "universal/",
# Build Target (dolphin-emu to just build the emulator and skip the tests)
"build_target": "ALL_BUILD",
# Locations to pkg config files for arm and x64 libraries
# The default values of these paths are taken from the default
# paths used for homebrew
"arm64_pkg_config_path": '/opt/homebrew/lib/pkgconfig',
"x86_64_pkg_config_path": '/usr/local/lib/pkgconfig',
# Locations to qt5 directories for arm and x64 libraries
# The default values of these paths are taken from the default
# paths used for homebrew
"arm64_qt5_path": '/opt/homebrew/opt/qt5',
"x86_64_qt5_path": '/usr/local/opt/qt5',
# Identity to use for code signing. "-" indicates that the app will not
# be cryptographically signed/notarized but will instead just use a
# SHA checksum to verify the integrity of the app. This doesn't
# protect against malicious actors, but it does protect against
# running corrupted binaries and allows for access to the extended
# permisions needed for ARM builds
"codesign_identity": '-',
# Etitlements file to use for code signing
"entitlements": "../Source/Core/DolphinQt/DolphinEmu.entitlements",
# Minimum macOS version for each architecture slice
"arm64_mac_os_deployment_target": "11.0.0",
"x86_64_mac_os_deployment_target": "10.12.0"
}
# # END CONFIG # #
# Architectures to build for. This is explicity left out of the command line
# config options for several reasons:
# 1) Adding new architectures will generally require more code changes
# 2) Single architecture builds should utilize the normal generated cmake
# project files rather than this wrapper script
ARCHITECTURES = ["x86_64", "arm64"]
def parse_args(default_conf=DEFAULT_CONFIG):
"""
Parses the command line arguments into a config dictionary.
"""
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument(
'--target',
help='Build target in generated project files',
default=default_conf["build_target"],
dest="build_target")
parser.add_argument(
'--dst_app',
help='Directory where universal binary will be stored',
default=default_conf["dst_app"])
parser.add_argument(
'--entitlements',
help='Path to .entitlements file for code signing',
default=default_conf["entitlements"])
parser.add_argument(
'--codesign',
help='Code signing identity to use to sign the applications',
default=default_conf["codesign_identity"],
dest="codesign_identity")
for arch in ARCHITECTURES:
parser.add_argument(
'--{}_pkg_config'.format(arch),
help="Folder containing .pc files for {} libraries".format(arch),
default=default_conf[arch+"_pkg_config_path"],
dest=arch+"_pkg_config_path")
parser.add_argument(
'--{}_qt5_path'.format(arch),
help="Install path for {} qt5 libraries".format(arch),
default=default_conf[arch+"_qt5_path"])
parser.add_argument(
'--{}_mac_os_deployment_target'.format(arch),
help="Deployment architecture for {} slice".format(arch),
default=default_conf[arch+"_mac_os_deployment_target"])
return vars(parser.parse_args())
def lipo(path0, path1, dst):
if subprocess.call(['lipo', '-create', '-output', dst, path0, path1]) != 0:
print("WARNING: {} and {} can not be lipo'd, keeping {}"
.format(path0, path1, path0))
shutil.copy(path0, dst)
def recursiveMergeBinaries(src0, src1, dst):
"""
Merges two build trees together for different architectures into a single
universal binary.
The rules for merging are:
1) Files that exist in either src tree are copied into the dst tree
2) Files that exist in both trees and are identical are copied over
unmodified
3) Files that exist in both trees and are non-identical are lipo'd
4) Symlinks are created in the destination tree to mirror the hierarchy in
the source trees
"""
# loop over all files in src0
for newpath0 in glob.glob(src0+"/*"):
filename = os.path.basename(newpath0)
newpath1 = os.path.join(src1, filename)
new_dst_path = os.path.join(dst, filename)
if os.path.islink(newpath0):
# symlinks will be fixed after files are resolved
continue
if not os.path.exists(newpath1):
# copy files that don't exist in path1
shutil.copy(newpath0, new_dst_path)
continue
if os.path.isdir(newpath1):
os.mkdir(new_dst_path)
# recurse into directories
recursiveMergeBinaries(newpath0, newpath1, new_dst_path)
continue
if filecmp.cmp(newpath0, newpath1):
# copy files that are the same
shutil.copy(newpath0, new_dst_path)
else:
# lipo together files that are different
lipo(newpath0, newpath1, new_dst_path)
# loop over files in src1 and copy missing things over to dst
for newpath1 in glob.glob(src1+"/*"):
filename = os.path.basename(newpath0)
newpath0 = os.path.join(src0, filename)
new_dst_path = os.path.join(dst, filename)
if not os.path.exists(newpath0) and not os.path.islink(newpath1):
shutil.copytree(newpath1, new_dst_path)
# fix up symlinks for path0
for newpath0 in glob.glob(src0+"/*"):
filename = os.path.basename(newpath0)
new_dst_path = os.path.join(dst, filename)
if os.path.islink(newpath0):
relative_path = os.path.relpath(os.path.realpath(newpath0), src0)
os.symlink(relative_path, new_dst_path)
# fix up symlinks for path1
for newpath1 in glob.glob(src1+"/*"):
filename = os.path.basename(newpath1)
new_dst_path = os.path.join(dst, filename)
newpath0 = os.path.join(src0, filename)
if os.path.islink(newpath1) and not os.path.exists(newpath0):
relative_path = os.path.relpath(os.path.realpath(newpath1), src1)
os.symlink(relative_path, new_dst_path)
def build(config):
"""
Builds the project with the parameters specified in config.
"""
print("Building config:")
print(json.dumps(config, indent=4))
dst_app = config["dst_app"]
# Configure and build single architecture builds for each architecture
for arch in ARCHITECTURES:
# Create build directory for architecture
if not os.path.exists(arch):
os.mkdir(arch)
# Setup environment variables for build
envs = os.environ.copy()
envs['PKG_CONFIG_PATH'] = config[arch+"_pkg_config_path"]
envs['Qt5_DIR'] = config[arch+"_qt5_path"]
envs['CMAKE_OSX_ARCHITECTURES'] = arch
subprocess.check_call([
'arch', '-'+arch,
'cmake', '../../', '-G', 'Xcode',
'-DCMAKE_OSX_DEPLOYMENT_TARGET='
+ config[arch+"_mac_os_deployment_target"],
'-DMACOS_CODE_SIGNING_IDENTITY='
+ config['codesign_identity'],
'-DMACOS_CODE_SIGNING_IDENTITY_UPDATER='
+ config['codesign_identity'],
'-DMACOS_CODE_SIGNING="ON"'
],
env=envs, cwd=arch)
# Build project
subprocess.check_call(['xcodebuild',
'-project', 'dolphin-emu.xcodeproj',
'-target', config["build_target"],
'-configuration', 'Release'], cwd=arch)
# Source binary trees to merge together
src_app0 = ARCHITECTURES[0]+"/Binaries/release"
src_app1 = ARCHITECTURES[1]+"/Binaries/release"
if os.path.exists(dst_app):
shutil.rmtree(dst_app)
os.mkdir(dst_app)
# create univeral binary
recursiveMergeBinaries(src_app0, src_app1, dst_app)
# codesign the universal binary
for path in glob.glob(dst_app+"/*"):
subprocess.check_call([
'codesign',
'-d',
'--force',
'-s',
config["codesign_identity"],
'--options', 'runtime',
'--entitlements', config["entitlements"],
'--deep',
'--verbose=2',
path])
if __name__ == "__main__":
conf = parse_args()
build(conf)
print("Built Universal Binary successfully!")

View File

@ -6,8 +6,12 @@ cmake_minimum_required(VERSION 3.10)
# Minimum OS X version.
# This is inserted into the Info.plist as well.
# MacOS prior to 10.14 did not fully support C++17, which is used to
# handle configuration options and aligned alloc
# MacOS prior to 10.14 did not support aligned alloc which is used to implement
# std::unique_ptr in the arm64 C++ standard library. x86_64 builds can override
# this to 10.12.0 using -DCMAKE_OSX_DEPLOYMENT_TARGET="10.12.0" without issue.
# This is done in the universal binary building script to build a binary that
# runs on 10.12 on x86_64 computers, while still containing an arm64 slice.
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14.0" CACHE STRING "")
set(CMAKE_USER_MAKE_RULES_OVERRIDE "CMake/FlagsOverride.cmake")
@ -68,8 +72,12 @@ else()
endif()
if(APPLE)
option(OSX_USE_DEFAULT_SEARCH_PATH "Don't prioritize system library paths" OFF)
option(MACOS_USE_DEFAULT_SEARCH_PATH "Don't prioritize system library paths" OFF)
option(SKIP_POSTPROCESS_BUNDLE "Skip postprocessing bundle for redistributability" OFF)
# Enable adhoc code signing by default (otherwise makefile builds on ARM will not work)
option(MACOS_CODE_SIGNING "Enable codesigning" ON)
set(MACOS_CODE_SIGNING_IDENTITY "-" CACHE STRING "The identity used for codesigning.")
set(MACOS_CODE_SIGNING_IDENTITY_UPDATER "-" CACHE STRING "The identity used for codesigning, for the updater.")
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
@ -290,7 +298,7 @@ else()
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Darwin")
if(NOT OSX_USE_DEFAULT_SEARCH_PATH)
if(NOT MACOS_USE_DEFAULT_SEARCH_PATH)
# Hack up the path to prioritize the path to built-in OS libraries to
# increase the chance of not depending on a bunch of copies of them
# installed by MacPorts, Fink, Homebrew, etc, and ending up copying

View File

@ -73,7 +73,7 @@ application bundle using the following steps:
4. Universal binaries will be available in the `universal` folder
Doing this requires installation of library dependencies for both x64 and ARM (or universal library
equilvalents) and may require modification of the config portion of the script to point to the
equivalents) and may require modification of the config portion of the script to point to the
library locations
A binary supporting a single architecture can be built as well using the following steps:

View File

@ -43,8 +43,7 @@ void* AllocateExecutableMemory(size_t size)
#if defined(_M_ARM_64) && defined(__APPLE__)
map_flags |= MAP_JIT;
#endif
void* ptr =
mmap(nullptr, size, PROT_READ | PROT_WRITE |PROT_EXEC , map_flags, -1, 0);
void* ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, map_flags, -1, 0);
if (ptr == MAP_FAILED)
ptr = nullptr;
#endif
@ -54,7 +53,19 @@ void* AllocateExecutableMemory(size_t size)
return ptr;
}
// Certain platforms (Mac OS X on ARM) enforce that a single thread can only have write or
// This function is used to provide a counter for the JITPageWrite*Execute*
// functions to enable nesting. The static variable is wrapped in a a function
// to allow those functions to be called inside of the constructor of a static
// variable portably.
//
// The variable is thread_local as the W^X mode is specific to each running thread.
static int& JITPageWriteNestCounter()
{
static thread_local int nest_counter = 0;
return nest_counter;
}
// Certain platforms (Mac OS on ARM) enforce that a single thread can only have write or
// execute permissions to pages at any given point of time. The two below functions
// are used to toggle between having write permissions or execute permissions.
//
@ -66,21 +77,53 @@ void* AllocateExecutableMemory(size_t size)
// PrepareInstructionStreamForJIT();
// JITPageWriteDisableExecuteEnable();
// These functions can be nested, in which case execution will only be enabled
// after the call to the JITPageWriteDisableExecuteEnable from the top most
// nesting level. Example:
// [JIT page is in execute mode for the thread]
// JITPageWriteEnableExecuteDisable();
// [JIT page is in write mode for the thread]
// JITPageWriteEnableExecuteDisable();
// [JIT page is in write mode for the thread]
// JITPageWriteDisableExecuteEnable();
// [JIT page is in write mode for the thread]
// JITPageWriteDisableExecuteEnable();
// [JIT page is in execute mode for the thread]
// Allows a thread to write to executable memory, but not execute the data.
void JITPageWriteEnableExecuteDisable(){
void JITPageWriteEnableExecuteDisable()
{
#if defined(_M_ARM_64) && defined(__APPLE__)
if (__builtin_available(macOS 11.0, *)) {
if (JITPageWriteNestCounter() == 0)
{
if (__builtin_available(macOS 11.0, *))
{
pthread_jit_write_protect_np(0);
}
}
#endif
JITPageWriteNestCounter()++;
}
// Allows a thread to execute memory allocated for execution, but not write to it.
void JITPageWriteDisableExecuteEnable(){
void JITPageWriteDisableExecuteEnable()
{
JITPageWriteNestCounter()--;
// Sanity check the NestCounter to identify underflow
// This can indicate the calls to JITPageWriteDisableExecuteEnable()
// are not matched with previous calls to JITPageWriteEnableExecuteDisable()
if (JITPageWriteNestCounter() < 0)
PanicAlertFmt("JITPageWriteNestCounter() underflowed");
#if defined(_M_ARM_64) && defined(__APPLE__)
if (__builtin_available(macOS 11.0, *)) {
if (JITPageWriteNestCounter() == 0)
{
if (__builtin_available(macOS 11.0, *))
{
pthread_jit_write_protect_np(1);
}
}
#endif
}

View File

@ -277,8 +277,7 @@ void DolphinAnalytics::MakeBaseBuilder()
builder.AddData("android-version", s_get_val_func("DEVICE_OS"));
#elif defined(__APPLE__)
builder.AddData("os-type", "osx");
//objc_msgSend is only available on x86
#ifndef _M_ARM_64
// id processInfo = [NSProcessInfo processInfo]
id processInfo = reinterpret_cast<id (*)(Class, SEL)>(objc_msgSend)(
objc_getClass("NSProcessInfo"), sel_getUid("processInfo"));
@ -290,17 +289,21 @@ void DolphinAnalytics::MakeBaseBuilder()
s64 minor_version; // NSInteger minorVersion
s64 patch_version; // NSInteger patchVersion
};
// Under arm64, we need to call objc_msgSend to recieve a struct.
// On x86_64, we need to explicitly call objc_msgSend_stret for a struct.
#if _M_ARM_64
#define msgSend objc_msgSend
#else
#define msgSend objc_msgSend_stret
#endif
// NSOperatingSystemVersion version = [processInfo operatingSystemVersion]
OSVersion version = reinterpret_cast<OSVersion (*)(id, SEL)>(objc_msgSend_stret)(
OSVersion version = reinterpret_cast<OSVersion (*)(id, SEL)>(msgSend)(
processInfo, sel_getUid("operatingSystemVersion"));
#undef msgSend
builder.AddData("osx-ver-major", version.major_version);
builder.AddData("osx-ver-minor", version.minor_version);
builder.AddData("osx-ver-bugfix", version.patch_version);
}
#endif
#elif defined(__linux__)
builder.AddData("os-type", "linux");
#elif defined(__FreeBSD__)

View File

@ -73,8 +73,8 @@ void JitArm64::Init()
bool JitArm64::HandleFault(uintptr_t access_address, SContext* ctx)
{
//Ifdef this since the exception handler runs on a separate thread on Mac OS X (ARM)
#if !defined(__APPLE__) && !defined(_M_ARM_64)
// Ifdef this since the exception handler runs on a separate thread on macOS (ARM)
#if !(defined(__APPLE__) && defined(_M_ARM_64))
// We can't handle any fault from other threads.
if (!Core::IsCPUThread())
{
@ -631,7 +631,6 @@ void JitArm64::Jit(u32)
DoJit(em_address, b, nextPC);
blocks.FinalizeBlock(*b, jo.enableBlocklink, code_block.m_physical_addresses);
Common::JITPageWriteDisableExecuteEnable();
}
void JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)

View File

@ -518,6 +518,22 @@ if(APPLE)
POST_BUILD COMMAND
${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/"
$<TARGET_FILE:dolphin-emu>)
if(MACOS_CODE_SIGNING)
# Code sign make file builds
add_custom_command(TARGET dolphin-emu
POST_BUILD COMMAND
/usr/bin/codesign -f -s "${MACOS_CODE_SIGNING_IDENTITY}" --deep --options runtime --entitlements ${CMAKE_SOURCE_DIR}/Source/Core/DolphinQt/DolphinEmu.entitlements "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Dolphin.app" || true)
# Code sign builds for build systems that do have release/debug variants (Xcode)
add_custom_command(TARGET dolphin-emu
POST_BUILD COMMAND
/usr/bin/codesign -f -s "${MACOS_CODE_SIGNING_IDENTITY}" --deep --options runtime --entitlements ${CMAKE_SOURCE_DIR}/Source/Core/DolphinQt/DolphinEmu.entitlements "${CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG}/Dolphin.app" || true)
add_custom_command(TARGET dolphin-emu
POST_BUILD COMMAND
/usr/bin/codesign -f -s "${MACOS_CODE_SIGNING_IDENTITY}" --deep --options runtime --entitlements ${CMAKE_SOURCE_DIR}/Source/Core/DolphinQt/DolphinEmu.entitlements "${CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE}/Dolphin.app" || true)
endif()
else()
install(TARGETS dolphin-emu RUNTIME DESTINATION ${bindir})
endif()

View File

@ -4,6 +4,13 @@
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<!-- Needed for GameCube microphone emulation -->
<key>com.apple.security.device.audio-input</key>
<true/>
<!-- TODO: It is likely this requirement is coming from Qt, but should confirm -->
<key>com.apple.security.automation.apple-events</key>
<true/>
<!-- This is needed to use adhoc signed linked libraries -->
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
</dict>

View File

@ -13,6 +13,8 @@ set(SOURCES
add_executable(MacUpdater ${SOURCES})
set(MacUpdater_NAME "Dolphin Updater")
set(MacUpdater_BIN_DIR ${CMAKE_BINARY_DIR}/Binaries)
set(MacUpdater_BUNDLE_PATH ${MacUpdater_BIN_DIR}/${MacUpdater_NAME}.app)
set_target_properties(MacUpdater PROPERTIES
MACOSX_BUNDLE true
@ -53,8 +55,24 @@ foreach(sb ${STORYBOARDS})
add_custom_command(TARGET MacUpdater POST_BUILD
COMMAND ${IBTOOL} --errors --warnings --notices --output-format human-readable-text
--compile ${MacUpdater_BIN_DIR}/${MacUpdater_NAME}.app/Contents/Resources/${sb}c
--compile ${MacUpdater_BUNDLE_PATH}/Contents/Resources/${sb}c
${CMAKE_CURRENT_SOURCE_DIR}/${sb}
COMMENT "Compiling Storyboard ${sb}...")
endforeach()
if(MACOS_CODE_SIGNING)
if (MACOS_CODE_SIGNING_IDENTITY_UPDATER STREQUAL "")
set(MACOS_CODE_SIGNING_IDENTITY_UPDATER "${MACOS_CODE_SIGNING_IDENTITY}")
endif()
# Make file build code sign
add_custom_command(TARGET MacUpdater POST_BUILD
COMMAND test ${MacUpdater_BUNDLE_PATH} || /usr/bin/codesign -f -s "${MACOS_CODE_SIGNING_IDENTITY_UPDATER}" --deep --options runtime ${MacUpdater_BUNDLE_PATH})
# Xcode build code sign
add_custom_command(TARGET MacUpdater POST_BUILD
COMMAND test "${CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG}/${MacUpdater_NAME}.app" || /usr/bin/codesign -f -s "${MACOS_CODE_SIGNING_IDENTITY_UPDATER}" --deep --options runtime "${CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG}/${MacUpdater_NAME}.app")
add_custom_command(TARGET MacUpdater POST_BUILD
COMMAND test "${CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE}/${MacUpdater_NAME}.app" || /usr/bin/codesign -f -s "${MACOS_CODE_SIGNING_IDENTITY_UPDATER}" --deep --options runtime "${CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE}/${MacUpdater_NAME}.app")
endif()