diff --git a/Docs/macOSSigning.md b/Docs/macOSSigning.md index 04033743..ffaffc68 100644 --- a/Docs/macOSSigning.md +++ b/Docs/macOSSigning.md @@ -11,10 +11,15 @@ - Select `Developer ID Application` - _This certificate is used to code sign your app for distribution outside of the Mac App Store._ +## Adding an existing certificate +1. Go to https://developer.apple.com/account/resources/certificates/download +1. Download `Developer ID Application` +2. Add certificate `System` + ## Sign the app locally with codesign We need to sign every single file in the .app file. For this we use the name from the installed cert. This can be copied from the `Keychain Access.app`. -`codesign --deep -f -s "Developer ID Application: Elias Steurer (AAABCXYZAA)" --options "runtime" "ScreenPlay.app/"` +`codesign --deep -f -s "Developer ID Application: Elias Steurer (V887LHYKRH)" --options "runtime" "ScreenPlay.app/"` ## Upload to apple for notization We use [xcnotary](https://github.com/akeru-inc/xcnotary) tools for fast automatic upload. Install it via brew: diff --git a/Tools/build.py b/Tools/build.py index 2e95db47..e2aaf7b3 100755 --- a/Tools/build.py +++ b/Tools/build.py @@ -110,6 +110,7 @@ def build( deploy_command: str = "" executable_file_ending: str = "" qt_path: str = "" + qt_bin_path: str = "" aqt_install_qt_packages: str = "" aqt_install_tool_packages: str = "" cmake_target_triplet: str = "" @@ -120,11 +121,12 @@ def build( cmake_target_triplet = "x64-windows" windows_msvc = "msvc2019_64" executable_file_ending = ".exe" - qt_path = aqt_path.joinpath(qt_version).joinpath( + qt_path = aqt_path if use_aqt else Path("C:/Qt") + qt_bin_path = aqt_path.joinpath(qt_version).joinpath( windows_msvc) if use_aqt else Path(f"C:/Qt/{qt_version}/{windows_msvc}") vs_env_dict = get_vs_env_dict() vs_env_dict["PATH"] = vs_env_dict["PATH"] + \ - ";" + str(qt_path) + "\\bin" + ";" + str(qt_bin_path) + "\\bin" os.environ.update(vs_env_dict) deploy_command = "windeployqt.exe --{type} --qmldir ../../{app}/qml {app}{executable_file_ending}" @@ -134,10 +136,13 @@ def build( elif platform.system() == "Darwin": if(build_architecture == "arm64"): cmake_target_triplet = "arm64-osx" - else: + elif(build_architecture == "x64"): cmake_target_triplet = "x64-osx" - - qt_path = aqt_path.joinpath( + else: + print("MISSING BUILD ARCH: SET arm64 or x64") + exit(1) + qt_path = aqt_path if use_aqt else Path("~/Qt/") + qt_bin_path = aqt_path.joinpath( f"{qt_version}/macos") if use_aqt else Path(f"~/Qt/{qt_version}/macos") deploy_command = "{prefix_path}/bin/macdeployqt {app}.app -qmldir=../../{app}/qml -executable={app}.app/Contents/MacOS/{app}" @@ -146,7 +151,8 @@ def build( elif platform.system() == "Linux": cmake_target_triplet = "x64-linux" - qt_path = aqt_path.joinpath( + qt_path = aqt_path if use_aqt else Path("~/Qt/") + qt_bin_path = aqt_path.joinpath( f"{qt_version}/gcc_64") if use_aqt else Path(f"~/Qt/{qt_version}/gcc_64") aqt_install_qt_packages = f"linux desktop {qt_version} gcc_64 -m all" aqt_install_tool_packages = "linux desktop tools_ifw" @@ -155,7 +161,7 @@ def build( else: print("cqtdeployer not available, build may be incomplete and incompatible with some distro (typically Ubuntu)") home_path = str(Path.home()) - qt_path = aqt_path.joinpath( + qt_bin_path = aqt_path.joinpath( f"{qt_version}/gcc_64") if use_aqt else Path(f"{home_path}/Qt/{qt_version}/gcc_64") else: raise NotImplementedError( @@ -163,7 +169,7 @@ def build( # Default to QtMaintainance installation. if use_aqt: - print(f"qt_path: {qt_path}.") + print(f"qt_bin_path: {qt_bin_path}.") if not Path(aqt_path).exists(): print( f"aqt path does not exist at {aqt_path}. Installing now into...") @@ -173,11 +179,18 @@ def build( # Prepare cmake_toolchain_file = f"'{root_path}/../ScreenPlay-vcpkg/scripts/buildsystems/vcpkg.cmake'" - ifw_root_path = f"{qt_path}\\Tools\\QtInstallerFramework\\{qt_ifw_version}" + ifw_root_path = f"{qt_path}/Tools/QtInstallerFramework/{qt_ifw_version}" print(f"cmake_toolchain_file: {cmake_toolchain_file}") print( f"Starting build with type {build_type}. Qt Version: {qt_version}. Root path: {root_path}") + + # Remove old build folder to before configuring to get rid of + # all cmake chaches + build_folder = root_path.joinpath( + f"build-{cmake_target_triplet}-{build_type}") + clean_build_dir(build_folder) + CMAKE_OSX_ARCHITECTURES: str = "" # The entire parameter should be optional. We need this to explicity build # x84 and arm version seperat, only because we cannot compile two at once with vcpkg @@ -186,7 +199,7 @@ def build( cmake_configure_command = f'cmake ../ \ {CMAKE_OSX_ARCHITECTURES} \ - -DCMAKE_PREFIX_PATH={qt_path} \ + -DCMAKE_PREFIX_PATH={qt_bin_path} \ -DCMAKE_BUILD_TYPE={build_type} \ -DVCPKG_TARGET_TRIPLET={cmake_target_triplet} \ -DCMAKE_TOOLCHAIN_FILE={cmake_toolchain_file} \ @@ -198,9 +211,6 @@ def build( -G "CodeBlocks - Ninja" \ -B.' - build_folder = root_path.joinpath( - f"build-{cmake_target_triplet}-{build_type}") - clean_build_dir(build_folder) # Build start_time = time.time() @@ -215,56 +225,56 @@ def build( print("Executing deploy commands...") run(deploy_command.format( type=build_type, - prefix_path=qt_path, + prefix_path=qt_bin_path, app="ScreenPlay", executable_file_ending=executable_file_ending), cwd=bin_dir) run(deploy_command.format( type=build_type, - prefix_path=qt_path, + prefix_path=qt_bin_path, app="ScreenPlayWidget", executable_file_ending=executable_file_ending), cwd=bin_dir) run(deploy_command.format( type=build_type, - prefix_path=qt_path, + prefix_path=qt_bin_path, app="ScreenPlayWallpaper", executable_file_ending=executable_file_ending), cwd=bin_dir) else: # just copy the folders and be done with it if platform.system() == "Linux": - # Copy all .so files from the qt_path lib folder into bin_dir - qt_lib_path = qt_path + # Copy all .so files from the qt_bin_path lib folder into bin_dir + qt_lib_path = qt_bin_path for file in qt_lib_path.joinpath("lib").glob("*.so"): shutil.copy(str(file), str(bin_dir)) # Copy qt_qml_path folder content into bin_dir - qt_qml_path = qt_path + qt_qml_path = qt_bin_path for folder in qt_qml_path.joinpath("qml").iterdir(): if not folder.is_file(): shutil.copytree(str(folder), str( bin_dir.joinpath(folder.name))) print("Copied %s" % folder) - # Copy all plugin folder from qt_path plugins subfolder into bin_dir - qt_plugins_path = qt_path - for folder in qt_path.joinpath("plugins").iterdir(): + # Copy all plugin folder from qt_bin_path plugins subfolder into bin_dir + qt_plugins_path = qt_bin_path + for folder in qt_bin_path.joinpath("plugins").iterdir(): if not folder.is_file(): shutil.copytree(str(folder), str( bin_dir.joinpath(folder.name))) print("Copied %s" % folder) - # Copy all folder from qt_path translation files into bin_dir translation folder - qt_translations_path = qt_path + # Copy all folder from qt_bin_path translation files into bin_dir translation folder + qt_translations_path = qt_bin_path for folder in qt_translations_path.joinpath("translations").iterdir(): if not folder.is_file(): shutil.copytree(str(folder), str( bin_dir.joinpath("translations").joinpath(folder.name))) print("Copied %s" % folder) - # Copy all filesfrom qt_path resources folder into bin_dir folder - qt_resources_path = qt_path - for file in qt_path.joinpath("resources").glob("*"): + # Copy all filesfrom qt_bin_path resources folder into bin_dir folder + qt_resources_path = qt_bin_path + for file in qt_bin_path.joinpath("resources").glob("*"): shutil.copy(str(file), str(bin_dir)) print("Copied %s" % file) diff --git a/Tools/build_and_publish.py b/Tools/build_and_publish.py index d4472f89..52102707 100644 --- a/Tools/build_and_publish.py +++ b/Tools/build_and_publish.py @@ -1,8 +1,10 @@ -import build +from build import build import steam_publish import argparse import os from pathlib import Path +from macos_lipo import run_lipo, check_fat_binary +import platform if __name__ == "__main__": parser = argparse.ArgumentParser(description='Build and Package ScreenPlay') @@ -12,21 +14,57 @@ if __name__ == "__main__": # Script needs to run in the tools folder tools_path = Path.cwd() os.chdir(tools_path) - build( - qt_version="6.4.0", - qt_ifw_version="4.4", - build_steam="ON", - build_tests="OFF", - build_release="ON", - create_installer="ON", - build_type="release", - sign_build=False, - use_aqt=False - ) + root_path = tools_path.parent + print(f"Set root directory to: {root_path}") + + if platform.system() == "Darwin": + # OSX builds needs to build for x86 and arm + # and also be signed! + build( + qt_version="6.4.0", + qt_ifw_version="4.4", + build_steam="ON", + build_tests="OFF", + build_release="ON", + create_installer="ON", + build_type="release", + sign_build=True, + use_aqt=False, + build_architecture = "arm64" + ) + build( + qt_version="6.4.0", + qt_ifw_version="4.4", + build_steam="ON", + build_tests="OFF", + build_release="ON", + create_installer="OFF", + build_type="release", + sign_build=True, + use_aqt=False, + build_architecture = "x64" + ) + # Make sure to reset to tools path + os.chdir(root_path) + # Create universal (fat) binary + run_lipo() + check_fat_binary() + else: + build( + qt_version="6.4.0", + qt_ifw_version="4.4", + build_steam="ON", + build_tests="OFF", + build_release="ON", + create_installer="OFF", + build_type="release", + sign_build=False, + use_aqt=False + ) # Make sure to reset to tools path os.chdir(tools_path) - steam_publish( - steam_username="tachiom", - steam_password=args.steam_password, - set_live_branch_name="internal" - ) + #steam_publish( + # steam_username="tachiom", + # steam_password=args.steam_password, + # set_live_branch_name="internal" + #) diff --git a/Tools/macos_lipo.py b/Tools/macos_lipo.py new file mode 100644 index 00000000..b7a4e452 --- /dev/null +++ b/Tools/macos_lipo.py @@ -0,0 +1,88 @@ +#!/usr/bin/python3 +import platform +import os +import subprocess +import shutil +import argparse +import time +import zipfile +from shutil import copytree +from pathlib import Path +from concurrent.futures import ThreadPoolExecutor +from datetime import datetime +from util import run + +def listfiles(path): + files = [] + extensions = ('.dylib', '.so','') + ignored = ('qmldir') + print(f"WALK: {path}") + for dirName, subdirList, fileList in os.walk(path): + dir = dirName.replace(path, '') + for fname in fileList: + if Path(fname).suffix in extensions and not fname in ignored: + file = path + os.path.join(dir, fname) + if(os.path.isfile(file)): + print(file) + files.append(file) + return files + + +def create_fat_binary(): + # Make sure the script is always started from the same folder + root_path = Path.cwd() + if root_path.name == "Tools": + root_path = root_path.parent + print(f"Change root directory to: {root_path}") + os.chdir(root_path) + + arm64_dir = 'build-arm64-osx-release/bin/ScreenPlay.app' + x64_dir = "build-x64-osx-release/bin/ScreenPlay.app" + arm64_files = listfiles( + str(Path.joinpath(root_path, arm64_dir))) + x64_files = listfiles(str(Path.joinpath(root_path, x64_dir))) + + for file in arm64_files: + run(f"lipo -info {file}") + + # print(arm64_files) + # print(x64_files) + +def run_lipo(): + # Make sure the script is always started from the same folder + root_path = Path.cwd() + if root_path.name == "Tools": + root_path = root_path.parent + print(f"Change root directory to: {root_path}") + os.chdir(root_path) + + shutil.copytree(str(Path.joinpath(root_path, "build-arm64-osx-release/bin/")) , + str(Path.joinpath(root_path, "build-universal-osx-release/bin/")) ) + + apps = ["ScreenPlay","ScreenPlayWallpaper", "ScreenPlayWidget"] + for app in apps: + arm64_dir = str(Path.joinpath(root_path, f"build-arm64-osx-release/bin/{app}.app/Contents/MacOS/{app}")) + x64_dir = str(Path.joinpath(root_path, f"build-x64-osx-release/bin/{app}.app/Contents/MacOS/{app}")) + universal_dir = str(Path.joinpath(root_path, f"build-universal-osx-release/bin/{app}.app/Contents/MacOS/{app}")) + run(f"lipo -create {arm64_dir} {x64_dir} -output {universal_dir}") + run(f"lipo -info {universal_dir}") + +def check_fat_binary(): + # Make sure the script is always started from the same folder + root_path = Path.cwd() + if root_path.name == "Tools": + root_path = root_path.parent + print(f"Change root directory to: {root_path}") + os.chdir(root_path) + + dir = 'build-universal-osx-release/bin/' + files = listfiles(str(Path.joinpath(root_path, dir))) + + for file in files: + run(f"lipo -info {file}") + + +if __name__ == "__main__": + run_lipo() + check_fat_binary() + #create_fat_binary() diff --git a/Tools/steamcmd/depot_build_mac.vdf b/Tools/steamcmd/depot_build_mac.vdf index f2492aae..05ffa36b 100644 --- a/Tools/steamcmd/depot_build_mac.vdf +++ b/Tools/steamcmd/depot_build_mac.vdf @@ -5,7 +5,7 @@ // include all files recursively "FileMapping" { - "LocalPath" "build-x64-osx-release/bin/*" + "LocalPath" "build-universal-osx-release/bin/*" "DepotPath" "." "recursive" "1" } diff --git a/Tools/steamcmd/depot_build_mac_arm.vdf b/Tools/steamcmd/depot_build_mac_arm.vdf deleted file mode 100644 index ff9375cc..00000000 --- a/Tools/steamcmd/depot_build_mac_arm.vdf +++ /dev/null @@ -1,13 +0,0 @@ -"DepotBuildConfig" -{ - "DepotID" "672872" - - // include all files recursively - "FileMapping" - { - "LocalPath" "build-arm64-osx-release/bin/*" - "DepotPath" "." - "recursive" "1" - } - -} \ No newline at end of file diff --git a/Tools/util.py b/Tools/util.py new file mode 100644 index 00000000..2961180f --- /dev/null +++ b/Tools/util.py @@ -0,0 +1,11 @@ + + +from pathlib import Path +import os +import subprocess + +def run(cmd, cwd=Path.cwd()): + result = subprocess.run(cmd, shell=True, cwd=cwd) + if result.returncode != 0: + raise RuntimeError(f"Failed to execute {cmd}") +