From 0f0e4e6acc3210ec7cfdbcf1a371b87a4699c17e Mon Sep 17 00:00:00 2001 From: Mirko Galimberti Date: Sat, 18 Apr 2020 17:04:56 +0200 Subject: [PATCH] MetalANGLE support --- kivy_ios/recipes/kivy/__init__.py | 10 ++++- kivy_ios/recipes/metalangle/__init__.py | 27 +++++++++++++ kivy_ios/recipes/sdl2/__init__.py | 25 +++++++++---- kivy_ios/toolchain.py | 50 +++++++++++++++---------- recipes/metalangle/__init__.py | 27 +++++++++++++ 5 files changed, 112 insertions(+), 27 deletions(-) create mode 100644 kivy_ios/recipes/metalangle/__init__.py create mode 100644 recipes/metalangle/__init__.py diff --git a/kivy_ios/recipes/kivy/__init__.py b/kivy_ios/recipes/kivy/__init__.py index c03e80bdd..de0e46aae 100644 --- a/kivy_ios/recipes/kivy/__init__.py +++ b/kivy_ios/recipes/kivy/__init__.py @@ -19,7 +19,7 @@ class KivyRecipe(CythonRecipe): depends = ["sdl2", "sdl2_image", "sdl2_mixer", "sdl2_ttf", "ios", "pyobjus", "python", "host_setuptools3"] python_depends = ["certifi"] - pbx_frameworks = ["OpenGLES", "Accelerate", "CoreMedia", "CoreVideo"] + pbx_frameworks = ["Accelerate", "CoreMedia", "CoreVideo"] pre_build_ext = True def get_recipe_env(self, arch): @@ -43,9 +43,17 @@ def _remove_line(lines, pattern): for line in lines[:]: if pattern in line: lines.remove(line) + + def _sub_pattern(lines, pattern_old, pattern_new): + for i, line in enumerate(lines[:]): + if pattern_old in line: + lines[i] = lines[i].replace(pattern_old, pattern_new) + with open(pyconfig) as fd: lines = fd.readlines() _remove_line(lines, "flags['libraries'] = ['GLESv2']") + _sub_pattern(lines, "OpenGLES", "MetalANGLE") + # _remove_line(lines, "c_options['use_sdl'] = True") with open(pyconfig, "w") as fd: fd.writelines(lines) diff --git a/kivy_ios/recipes/metalangle/__init__.py b/kivy_ios/recipes/metalangle/__init__.py new file mode 100644 index 000000000..3d6ea0a0a --- /dev/null +++ b/kivy_ios/recipes/metalangle/__init__.py @@ -0,0 +1,27 @@ +from kivy_ios.toolchain import Recipe, shprint +from os.path import join +import sh + + +class MetalAngleFramework(Recipe): + version = "master" + url = "https://github.com/kakashidinho/metalangle/archive/{version}.zip" + frameworks = [dict(name="MetalANGLE", path="ios/xcode/build/Release-{arch.sdk}/MetalANGLE.framework")] + + def prebuild_arch(self, arch): + if self.has_marker("thirdparty_downloaded"): + return + shprint(sh.sh, join(self.build_dir, "ios", "xcode", "fetchDependencies.sh")) + self.set_marker("thirdparty_downloaded") + + def build_arch(self, arch): + shprint(sh.xcodebuild, self.ctx.concurrent_xcodebuild, + "ONLY_ACTIVE_ARCH=NO", + "ARCHS={}".format(arch.arch), + "-sdk", arch.sdk, + "-project", "ios/xcode/OpenGLES.xcodeproj", + "-target", "MetalANGLE", + "-configuration", "Release") + + +recipe = MetalAngleFramework() diff --git a/kivy_ios/recipes/sdl2/__init__.py b/kivy_ios/recipes/sdl2/__init__.py index 359b57142..be8baaf6a 100644 --- a/kivy_ios/recipes/sdl2/__init__.py +++ b/kivy_ios/recipes/sdl2/__init__.py @@ -1,23 +1,34 @@ from kivy_ios.toolchain import Recipe, shprint import sh +from os.path import join class LibSDL2Recipe(Recipe): # version = "2.0.9" # url = "https://www.libsdl.org/release/SDL2-{version}.tar.gz" - version = "7cc4fc886d9e" - url = "https://hg.libsdl.org/SDL/archive/{version}.tar.gz" + version = "metalangle" + url = "https://github.com/misl6/SDL-mirror/archive/{version}.zip" library = "Xcode-iOS/SDL/build/Release-{arch.sdk}/libSDL2.a" include_dir = "include" - pbx_frameworks = [ - "OpenGLES", "AudioToolbox", "QuartzCore", "CoreGraphics", - "CoreMotion", "GameController", "AVFoundation", "Metal", - "UIKit"] + depends = ["metalangle"] + pbx_frameworks = ["AudioToolbox", "QuartzCore", "CoreGraphics", "CoreMotion", + "GameController", "AVFoundation", "Metal", "UIKit", "MetalANGLE"] def prebuild_arch(self, arch): if self.has_marker("patched"): return - self.apply_patch("uikit-transparent.patch") + # self.apply_patch("uikit-transparent.patch") + + def _sub_pattern(lines, pattern_old, pattern_new): + for i, line in enumerate(lines[:]): + if pattern_old in line: + lines[i] = lines[i].replace(pattern_old, pattern_new) + sdl2pbxproj = join(self.build_dir, "Xcode-iOS", "SDL", "SDL.xcodeproj", "project.pbxproj") + with open(sdl2pbxproj) as fd: + lines = fd.readlines() + _sub_pattern(lines, "--YOURFRAMEMETALANGLEWORKPATH--", join(self.ctx.dist_dir, 'frameworks')) + with open(sdl2pbxproj, "w") as fd: + fd.writelines(lines) self.set_marker("patched") def build_arch(self, arch): diff --git a/kivy_ios/toolchain.py b/kivy_ios/toolchain.py index 7628773c0..79b4fc6d6 100755 --- a/kivy_ios/toolchain.py +++ b/kivy_ios/toolchain.py @@ -811,8 +811,13 @@ def build_all(self): self.make_lipo(static_fn, library) logger.info("Install include files for {}".format(self.name)) self.install_include() - logger.info("Install frameworks for {}".format(self.name)) - self.install_frameworks() + if self.frameworks: + logger.info("Make lipo framework for {}".format(self.name)) + for framework in self.frameworks: + framework_fn = join(self.ctx.dist_dir, "frameworks", "{}.framework".format(framework['name'])) + ensure_dir(dirname(framework_fn)) + logger.info(" - Lipo-ize {}".format(framework['name'])) + self.make_lipo_framework(framework_fn, framework) logger.info("Install sources for {}".format(self.name)) self.install_sources() logger.info("Install python deps for {}".format(self.name)) @@ -865,19 +870,24 @@ def make_lipo(self, filename, library=None): shprint(sh.lipo, "-create", "-output", filename, *args) @cache_execution - def install_frameworks(self): - if not self.frameworks: + def make_lipo_framework(self, filename, framework=None): + if framework is None: + framework = self.framework + if not framework: return - arch = self.filtered_archs[0] - build_dir = self.get_build_dir(arch.arch) - for framework in self.frameworks: - logger.info("Install Framework {}".format(framework)) - src = join(build_dir, framework) - dest = join(self.ctx.dist_dir, "frameworks", framework) - ensure_dir(dirname(dest)) - shutil.rmtree(dest, ignore_errors=True) - logger.debug("Copy {} to {}".format(src, dest)) - shutil.copytree(src, dest) + args = [] + ensure_dir(filename) + for arch in self.filtered_archs: + framework_p = framework['path'].format(arch=arch) + args += [join(self.get_build_dir(arch.arch), framework_p, framework['name'])] + logger.info("Copy the framework folder for Headers, Info.plst, etc in place") + shprint(sh.cp, "-r", + join(self.get_build_dir(self.filtered_archs[0].arch), + framework['path'].format(arch=self.filtered_archs[0])), + join(self.ctx.dist_dir, "frameworks")) + shprint(sh.rm, join(filename, framework['name'])) + logger.info("Lipo-ize the framework") + shprint(sh.lipo, "-create", "-output", join(filename, framework['name']), *args) @cache_execution def install_sources(self): @@ -1208,17 +1218,19 @@ def update_pbxproj(filename, pbx_frameworks=None): group = project.get_or_create_group("Frameworks") g_classes = project.get_or_create_group("Classes") file_options = FileOptions(embed_framework=False, code_sign_on_copy=True) + file_options_embed = FileOptions(embed_framework=True, code_sign_on_copy=True) for framework in pbx_frameworks: - framework_name = "{}.framework".format(framework) - if framework_name in frameworks: + if framework in [x['name'] for x in frameworks]: logger.info("Ensure {} is in the project (pbx_frameworks, local)".format(framework)) - f_path = join(ctx.dist_dir, "frameworks", framework_name) + f_path = join(ctx.dist_dir, "frameworks", f"{framework}.framework") + project.add_file(f_path, parent=group, tree="DEVELOPER_DIR", + force=False, file_options=file_options_embed) else: logger.info("Ensure {} is in the project (pbx_frameworks, system)".format(framework)) f_path = join(sysroot, "System", "Library", "Frameworks", "{}.framework".format(framework)) - project.add_file(f_path, parent=group, tree="DEVELOPER_DIR", - force=False, file_options=file_options) + project.add_file(f_path, parent=group, tree="DEVELOPER_DIR", + force=False, file_options=file_options) for library in pbx_libraries: logger.info("Ensure {} is in the project (pbx_libraries, dylib+tbd)".format(library)) f_path = join(sysroot, "usr", "lib", diff --git a/recipes/metalangle/__init__.py b/recipes/metalangle/__init__.py new file mode 100644 index 000000000..357719560 --- /dev/null +++ b/recipes/metalangle/__init__.py @@ -0,0 +1,27 @@ +from toolchain import Recipe, shprint +from os.path import join +import sh + + +class MetalAngleFramework(Recipe): + version = "master" + url = "https://github.com/kakashidinho/metalangle/archive/{version}.zip" + frameworks = [dict(name="MetalANGLE", path="ios/xcode/build/Release-{arch.sdk}/MetalANGLE.framework")] + + def prebuild_arch(self, arch): + if self.has_marker("thirdparty_downloaded"): + return + shprint(sh.sh, join(self.build_dir, "ios", "xcode", "fetchDependencies.sh")) + self.set_marker("thirdparty_downloaded") + + def build_arch(self, arch): + shprint(sh.xcodebuild, self.ctx.concurrent_xcodebuild, + "ONLY_ACTIVE_ARCH=NO", + "ARCHS={}".format(arch.arch), + "-sdk", arch.sdk, + "-project", "ios/xcode/OpenGLES.xcodeproj", + "-target", "MetalANGLE", + "-configuration", "Release") + + +recipe = MetalAngleFramework()