mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-24 06:51:17 +01:00
4ecb3084b7
This commit adds support for compiling Dolphin for ARM on MacOS so that it can run natively on the M1 processors without running through Rosseta2 emulation providing a 30-50% performance speedup and less hitches from Rosseta2. It consists of several key changes: - Adding support for W^X allocation(MAP_JIT) for the ARM JIT - Adding the machine context and config info to identify the M1 processor - Additions to the build system and docs to support building universal binaries - Adding code signing entitlements to access the MAP_JIT functionality - Updating the MoltenVK libvulkan.dylib to a newer version with M1 support
147 lines
5.5 KiB
Python
147 lines
5.5 KiB
Python
"""
|
|
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 +"/*");
|