From ac5c67e74851a4f9c31de39f08e8705f26f581e2 Mon Sep 17 00:00:00 2001 From: Cruor99 Date: Sun, 10 Dec 2017 15:56:08 +0100 Subject: [PATCH 01/42] Fix unicode error introduced in latest macOS --- toolchain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolchain.py b/toolchain.py index 133bac6..fcea038 100755 --- a/toolchain.py +++ b/toolchain.py @@ -37,7 +37,7 @@ def shprint(command, *args, **kwargs): kwargs["_out_bufsize"] = 1 kwargs["_err_to_out"] = True for line in command(*args, **kwargs): - stdout.write(line) + stdout.write(line.encode("ascii", "replace").decode()) def cache_execution(f): From b96498a9b429efc57075cfd659478ae5c3abb6f2 Mon Sep 17 00:00:00 2001 From: amru rosyada Date: Sat, 17 Mar 2018 06:11:56 +0700 Subject: [PATCH 02/42] fix error when call recipe list "toolchain.py recipes" --- toolchain.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/toolchain.py b/toolchain.py index 133bac6..818da58 100755 --- a/toolchain.py +++ b/toolchain.py @@ -1167,9 +1167,12 @@ Xcode: else: ctx = Context() for name in Recipe.list_recipes(): - recipe = Recipe.get_recipe(name, ctx) - print("{recipe.name:<12} {recipe.version:<8}".format( - recipe=recipe)) + try: + recipe = Recipe.get_recipe(name, ctx) + print("{recipe.name:<12} {recipe.version:<8}".format(recipe=recipe)) + + except: + pass def clean(self): parser = argparse.ArgumentParser( From 4fec0f68ff1225241f7c8122487b1669acbc450c Mon Sep 17 00:00:00 2001 From: amru rosyada Date: Sat, 17 Mar 2018 06:16:29 +0700 Subject: [PATCH 03/42] fixing error TypeError: 'dict_keys' object is not subscriptable --- toolchain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolchain.py b/toolchain.py index 818da58..a3f2a5e 100755 --- a/toolchain.py +++ b/toolchain.py @@ -103,7 +103,7 @@ class JsonStore(object): return self.data.keys() def remove_all(self, prefix): - for key in self.data.keys()[:]: + for key in tuple(self.data.keys()): if not key.startswith(prefix): continue del self.data[key] From 2c9e28f416675b7df0974cdc9f685e48ed717bd5 Mon Sep 17 00:00:00 2001 From: amru rosyada Date: Sat, 17 Mar 2018 12:04:20 +0700 Subject: [PATCH 04/42] add python 3 support detection, in case using python 3 in venv --- tools/external/mod_pbxproj.py | 132 +++++++++++++++++++++++++++------- 1 file changed, 106 insertions(+), 26 deletions(-) diff --git a/tools/external/mod_pbxproj.py b/tools/external/mod_pbxproj.py index bbb15b5..dfbfe90 100755 --- a/tools/external/mod_pbxproj.py +++ b/tools/external/mod_pbxproj.py @@ -36,14 +36,28 @@ import datetime import json import ntpath import os -import plistlib import re import shutil import subprocess import uuid +import plistlib -from UserDict import IterableUserDict -from UserList import UserList +try: + from UserDict import IterableUserDict + from UserList import UserList + +except: + # python 3 support + from collections import UserDict as IterableUserDict + from collections import UserList + +try: + from plistlib import PlistWriter + +except: + # python 3 support + from plistlib import _PlistWriter as PlistWriter + basestring = str regex = '[a-zA-Z0-9\\._/-]*' @@ -127,7 +141,7 @@ class PBXType(PBXDict): if cls and issubclass(cls, PBXType): return cls(o) - print 'warning: unknown PBX type: %s' % isa + print('warning: unknown PBX type: %s' % isa) return PBXDict(o) else: return o @@ -203,8 +217,8 @@ class PBXFileReference(PBXType): self.build_phase = build_phase if f_type == '?' and not ignore_unknown_type: - print 'unknown file extension: %s' % ext - print 'please add extension and Xcode type to PBXFileReference.types' + print('unknown file extension: %s' % ext) + print('please add extension and Xcode type to PBXFileReference.types') return f_type @@ -217,7 +231,7 @@ class PBXFileReference(PBXType): @classmethod def Create(cls, os_path, tree='SOURCE_ROOT', ignore_unknown_type=False): if tree not in cls.trees: - print 'Not a valid sourceTree type: %s' % tree + print('Not a valid sourceTree type: %s' % tree) return None fr = cls() @@ -565,11 +579,18 @@ class XcodeProject(PBXDict): root_group_id = self.root_object.get('mainGroup') self.root_group = self.objects[root_group_id] else: - print "error: project has no root object" + print("error: project has no root object") self.root_object = None self.root_group = None - for k, v in self.objects.iteritems(): + try: + objectList = self.objects.iteritems() + + except: + # python 3 support + objectList = self.objects.items() + + for k, v in objectList: v.id = k def add_other_cflags(self, flags): @@ -991,10 +1012,10 @@ class XcodeProject(PBXDict): def apply_patch(self, patch_path, xcode_path): if not os.path.isfile(patch_path) or not os.path.isdir(xcode_path): - print 'ERROR: couldn\'t apply "%s" to "%s"' % (patch_path, xcode_path) + print('ERROR: couldn\'t apply "%s" to "%s"' % (patch_path, xcode_path)) return - print 'applying "%s" to "%s"' % (patch_path, xcode_path) + print('applying "%s" to "%s"' % (patch_path, xcode_path)) return subprocess.call(['patch', '-p1', '--forward', '--directory=%s' % xcode_path, '--input=%s' % patch_path]) @@ -1269,14 +1290,31 @@ class XcodeProject(PBXDict): else: out.write(' ') - for key in sorted(root.iterkeys()): # keep the same order as Apple. + try: + iterKeys = root.iterkeys() + + except: + # python 3 support + iterkeys = root.keys() + + for key in sorted(iterkeys): # keep the same order as Apple. if enters: out.write('\t' + deep) if re.match(regex, key).group(0) == key: - out.write(key.encode("utf-8") + ' = ') + try: + out.write(key.encode("utf-8") + ' = ') + + except: + # python 3 support + out.write(key + ' = ') else: - out.write('"' + key.encode("utf-8") + '" = ') + try: + out.write('"' + key.encode("utf-8") + '" = ') + + except: + # python 3 support + out.write('"' + key + '" = ') if key == 'objects': out.write('{') # open the objects section @@ -1309,7 +1347,13 @@ class XcodeProject(PBXDict): continue out.write('\n/* Begin %s section */' % section[0].encode("utf-8")) - self.sections.get(section[0]).sort(cmp=lambda x, y: cmp(x[0], y[0])) + + try: + self.sections.get(section[0]).sort(cmp=lambda x, y: cmp(x[0], y[0])) + + except: + # python 3 support + self.sections.get(section[0]).sort(key=lambda elem: elem[0]) for pair in self.sections.get(section[0]): key = pair[0] @@ -1319,16 +1363,31 @@ class XcodeProject(PBXDict): if enters: out.write('\t\t' + deep) - out.write(key.encode("utf-8")) + try: + out.write(key.encode("utf-8")) + + except: + # python 3 support + out.write(key) if key in self.uuids: - out.write(" /* " + self.uuids[key].encode("utf-8") + " */") + try: + out.write(" /* " + self.uuids[key].encode("utf-8") + " */") + + except: + # python 3 support + out.write(" /* " + self.uuids[key] + " */") out.write(" = ") self._printNewXCodeFormat(out, value, '\t\t' + deep, enters=section[1]) out.write(';') - out.write('\n/* End %s section */\n' % section[0].encode("utf-8")) + try: + out.write('\n/* End %s section */\n' % section[0].encode("utf-8")) + + except: + # python 3 support + out.write('\n/* End %s section */\n' % section[0]) out.write(deep + '\t}') # close of the objects section else: @@ -1371,12 +1430,28 @@ class XcodeProject(PBXDict): else: if len(root) > 0 and re.match(regex, root).group(0) == root: - out.write(root.encode("utf-8")) + try: + out.write(root.encode("utf-8")) + + except: + # python 3 support + out.write(root) + else: - out.write('"' + XcodeProject.addslashes(root.encode("utf-8")) + '"') + try: + out.write('"' + XcodeProject.addslashes(root.encode("utf-8")) + '"') + + except: + # python 3 support + out.write('"' + XcodeProject.addslashes(root) + '"') if root in self.uuids: - out.write(" /* " + self.uuids[root].encode("utf-8") + " */") + try: + out.write(" /* " + self.uuids[root].encode("utf-8") + " */") + + except: + # python 3 support + out.write(" /* " + self.uuids[root] + " */") @classmethod def Load(cls, path): @@ -1391,10 +1466,15 @@ class XcodeProject(PBXDict): # If the plist was malformed, returncode will be non-zero if p.returncode != 0: - print stdout + print(stdout) return None - tree = plistlib.readPlistFromString(stdout) + try: + tree = plistlib.readPlistFromString(stdout) + + except: + tree = plistlib.loads(stdout) + return XcodeProject(tree, path) @classmethod @@ -1405,12 +1485,12 @@ class XcodeProject(PBXDict): # The code below was adapted from plistlib.py. -class PBXWriter(plistlib.PlistWriter): +class PBXWriter(PlistWriter): def writeValue(self, value): if isinstance(value, (PBXList, PBXDict)): - plistlib.PlistWriter.writeValue(self, value.data) + PlistWriter.writeValue(self, value.data) else: - plistlib.PlistWriter.writeValue(self, value) + PlistWriter.writeValue(self, value) def simpleElement(self, element, value=None): """ From 4eca2c46b1f430ecfe4f5c21acf2830299bdb913 Mon Sep 17 00:00:00 2001 From: Lawrence Du Date: Wed, 23 May 2018 09:23:21 -0700 Subject: [PATCH 05/42] Added kivent_core and cymunk recipes. Added *~ to .gitignore to prevent pushing emacs temporary files. --- recipes/cymunk/__init__.py | 48 +++++++++++++++ recipes/kivent_core/__init__.py | 105 ++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 recipes/cymunk/__init__.py create mode 100644 recipes/kivent_core/__init__.py diff --git a/recipes/cymunk/__init__.py b/recipes/cymunk/__init__.py new file mode 100644 index 0000000..6dac43a --- /dev/null +++ b/recipes/cymunk/__init__.py @@ -0,0 +1,48 @@ +from toolchain import CythonRecipe,shprint +import os +from os.path import join +import sh + +class CymunkRecipe(CythonRecipe): + version = 'master' + url = 'https://github.com/tito/cymunk/archive/{version}.zip' + name = 'cymunk' + depends = ['hostpython'] + cythonize = True + + def build_arch(self, arch): + """ + Override build.arch to avoid calling setup.py here (Call it in + install() instead). + """ + self.cythonize_build() + self.biglink() + + + def install(self): + """ + Do the equivalent of + python setup.py build_ext install + while setting the proper environment variables + + """ + arch = list(self.filtered_archs)[0] + build_env = self.get_recipe_env(arch) + hostpython = sh.Command(self.ctx.hostpython) + subdir_path = self.get_build_dir(arch.arch) + setup_path = join(subdir_path,"setup.py") + dest_dir = join (self.ctx.dist_dir, "root", "python") + build_env['PYTHONPATH'] = join(dest_dir, 'lib', 'python2.7', 'site-packages') + + #Note: Throws error if PATH is not set. I am not sure if this will cause problems + # in other architectures. + build_env['PATH']= os.environ.get('PATH') + + shprint(hostpython, + setup_path, + "build_ext", + #"--compiler=mingw32", #note: throws clang error + "install", + _env=build_env) + +recipe = CymunkRecipe() diff --git a/recipes/kivent_core/__init__.py b/recipes/kivent_core/__init__.py new file mode 100644 index 0000000..f363d20 --- /dev/null +++ b/recipes/kivent_core/__init__.py @@ -0,0 +1,105 @@ +""" +Author: Lawrence Du +E-mail: larrydu88@gmail.com +""" + +from toolchain import CythonRecipe, shprint +import sh +from os.path import join +from os import environ, chdir, + + + +class KiventCoreRecipe(CythonRecipe): + version = 'master' + url = 'https://github.com/kivy/kivent/archive/{version}.zip' + name = 'kivent_core' + depends = ['libffi','kivy'] #note: unsure if libffi is necessary here + pre_build_ext=False + subbuilddir = False + cythonize = True + pbx_frameworks = ["OpenGLES"] #note: This line may be unnecessary + + + def get_recipe_env(self, arch): + env = super(KiventCoreRecipe,self).get_recipe_env(arch) + env['CYTHONPATH'] = self.get_recipe( + 'kivy', self.ctx).get_build_dir(arch.arch) + return env + + + def get_build_dir(self,arch, sub=False): + """ + Call this to get the correct build_dir, where setup.py is located which is + actually under modules/core/setup.py + """ + builddir = super(KiventCoreRecipe, self).get_build_dir(str(arch)) + if sub or self.subbuilddir: + core_build_dir = join (builddir, 'modules', 'core') + print "Core build directory is located at {}".format(core_build_dir) + return core_build_dir + else: + print "Building in {}".format(builddir) + return builddir + + + def build_arch(self, arch): + """ + Override build.arch to avoid calling setup.py here (Call it in + install() instead). + """ + + self.subbuildir = True + self.cythonize_build() + self.biglink() + self.subbuilddir=False + + + def install(self): + """ + This method simply builds the command line call for calling + kivent_core/modules/core/setup.py + + This constructs the equivalent of the command + "$python2.7 setup.py build_ext install" + only with the environment variables altered for each different architecture + The appropriate version of kivy also needs to be added to the path, and this + differs for each architecture (i386, x86_64, armv7, etc) + + Note: This method is called by build_all() in toolchain.py + + """ + arch = list(self.filtered_archs)[0] + + build_dir = self.get_build_dir(arch.arch,sub=True) + print "Building kivent_core {} in {}".format(arch.arch,build_dir) + chdir(build_dir) + hostpython = sh.Command(self.ctx.hostpython) + + #Get the appropriate environment for this recipe (including CYTHONPATH) + #build_env = arch.get_env() + build_env = self.get_recipe_env(arch) + + dest_dir = join (self.ctx.dist_dir, "root", "python") + build_env['PYTHONPATH'] = join(dest_dir, 'lib', 'python2.7', 'site-packages') + + #Add Architecture specific kivy path for 'import kivy' to PYTHONPATH + arch_kivy_path = self.get_recipe('kivy', self.ctx).get_build_dir(arch.arch) + build_env['PYTHONPATH'] = join( build_env['PYTHONPATH'],':',arch_kivy_path) + + #Make sure you call kivent_core/modules/core/setup.py + subdir_path = self.get_build_dir(str(arch),sub=True) + setup_path = join(subdir_path,"setup.py") + + + #Print out directories for sanity check + print "ENVS", build_env + print "ROOT",self.ctx.root_dir + print "BUILD",self.ctx.build_dir + print "INCLUDE", self.ctx.include_dir + print "DISTDIR", self.ctx.dist_dir + print "ARCH KIVY LOC",self.get_recipe('kivy', self.ctx).get_build_dir(arch.arch) + + shprint(hostpython, setup_path, "build_ext", "install", _env=build_env) + +recipe = KiventCoreRecipe() From c3af68ad99712eb3c44f2eed9e8fed5e6b73b9f7 Mon Sep 17 00:00:00 2001 From: Lawrence Du Date: Wed, 23 May 2018 09:25:52 -0700 Subject: [PATCH 06/42] Added contact info to cymunk recipe --- recipes/cymunk/__init__.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/recipes/cymunk/__init__.py b/recipes/cymunk/__init__.py index 6dac43a..7676c49 100644 --- a/recipes/cymunk/__init__.py +++ b/recipes/cymunk/__init__.py @@ -1,3 +1,8 @@ +""" +Author: Lawrence Du +E-mail: larrydu88@gmail.com +""" + from toolchain import CythonRecipe,shprint import os from os.path import join From 71928646a261dac1a5be171ebe632eb34b7c2aa4 Mon Sep 17 00:00:00 2001 From: Lawrence Du Date: Wed, 23 May 2018 09:41:09 -0700 Subject: [PATCH 07/42] Added kivent_core and cymunk recipes. Added *~ to .gitignore. Fixed a typo in kivent_core/__init__.py imports. --- recipes/kivent_core/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipes/kivent_core/__init__.py b/recipes/kivent_core/__init__.py index f363d20..d25a515 100644 --- a/recipes/kivent_core/__init__.py +++ b/recipes/kivent_core/__init__.py @@ -6,7 +6,7 @@ E-mail: larrydu88@gmail.com from toolchain import CythonRecipe, shprint import sh from os.path import join -from os import environ, chdir, +from os import environ, chdir From 2674fc4ac02163b93b679827373db6d9053a4cda Mon Sep 17 00:00:00 2001 From: Charles Baynham Date: Thu, 14 Jun 2018 14:44:28 +0100 Subject: [PATCH 08/42] Add recipe for pykka --- recipes/pykka/__init__.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 recipes/pykka/__init__.py diff --git a/recipes/pykka/__init__.py b/recipes/pykka/__init__.py new file mode 100644 index 0000000..b0b66e2 --- /dev/null +++ b/recipes/pykka/__init__.py @@ -0,0 +1,13 @@ +from toolchain import PythonRecipe + + +class PykkaRecipe(PythonRecipe): + version = '1.2.1' + url = 'https://github.com/jodal/pykka/archive/v{version}.zip' + + depends = ['python', 'host_setuptools'] + + site_packages_name = 'pykka' + + +recipe = PykkaRecipe() From ea82e4358703c7781617d7697dd4b9b1fe41f8e8 Mon Sep 17 00:00:00 2001 From: Cruor99 Date: Wed, 18 Jul 2018 13:44:56 +0200 Subject: [PATCH 09/42] Fix typo in mod_pbxproj.py --- tools/external/mod_pbxproj.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/external/mod_pbxproj.py b/tools/external/mod_pbxproj.py index dfbfe90..ad3ad2c 100755 --- a/tools/external/mod_pbxproj.py +++ b/tools/external/mod_pbxproj.py @@ -1291,7 +1291,7 @@ class XcodeProject(PBXDict): out.write(' ') try: - iterKeys = root.iterkeys() + iterkeys = root.iterkeys() except: # python 3 support From aa01292d81a02ca732d3cc3128bcef9b7823a521 Mon Sep 17 00:00:00 2001 From: Peter Badida Date: Wed, 18 Jul 2018 22:50:15 +0200 Subject: [PATCH 10/42] Add explicit AttributeError for mod_pbxproj._printNewXCodeFormat In case issue similar to #295 appears again. --- tools/external/mod_pbxproj.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/external/mod_pbxproj.py b/tools/external/mod_pbxproj.py index ad3ad2c..ac4e15a 100755 --- a/tools/external/mod_pbxproj.py +++ b/tools/external/mod_pbxproj.py @@ -1293,7 +1293,7 @@ class XcodeProject(PBXDict): try: iterkeys = root.iterkeys() - except: + except AttributeError: # python 3 support iterkeys = root.keys() From 5a60fa58fe973bb7c78558fa0dc5c1ece5eedc3c Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Sat, 27 Oct 2018 16:21:15 +0200 Subject: [PATCH 11/42] fixes hostlibffi for latest xcode (removes 32 bits compilation unsupported by xcode, and fixes cache issues within xcode) --- recipes/hostlibffi/__init__.py | 22 +- recipes/hostlibffi/libffi-xcode10.patch | 391 ++++++++++++++++++++++++ toolchain.py | 2 +- 3 files changed, 407 insertions(+), 8 deletions(-) create mode 100644 recipes/hostlibffi/libffi-xcode10.patch diff --git a/recipes/hostlibffi/__init__.py b/recipes/hostlibffi/__init__.py index 77c2e0c..6f8e08e 100644 --- a/recipes/hostlibffi/__init__.py +++ b/recipes/hostlibffi/__init__.py @@ -1,5 +1,6 @@ from toolchain import Recipe, shprint import sh +from os.path import exists class LibffiRecipe(Recipe): @@ -31,22 +32,29 @@ class LibffiRecipe(Recipe): self.apply_patch("public_include.patch") self.apply_patch("staticlib.patch") self.apply_patch("staticlib2.patch") + self.apply_patch("libffi-xcode10.patch") self.set_marker("patched") def build_arch(self, arch): - shprint(sh.xcodebuild, self.ctx.concurrent_xcodebuild, + if exists("generate-darwin-source-and-headers.py"): + shprint( + sh.mv, + "generate-darwin-source-and-headers.py", + "_generate-darwin-source-and-headers.py") + shprint(sh.touch, "generate-darwin-source-and-headers.py") + shprint(sh.python2, "_generate-darwin-source-and-headers.py", "--only-osx") + shprint(sh.xcodebuild, + self.ctx.concurrent_xcodebuild, "ONLY_ACTIVE_ARCH=NO", "ARCHS={}".format(arch.arch), + "DSTROOT={}/hostlibffi".format(self.ctx.dist_dir), "-sdk", "macosx", - "install", "installhdrs", + "clean", "build", "installhdrs", "install", "-project", "libffi.xcodeproj", - "-target", "libffi-Mac", - "-configuration", "Release", - "DSTROOT={}/hostlibffi".format(self.ctx.dist_dir)) - + "-scheme", "libffi-Mac", + "-configuration", "Release") def postbuild_arch(self, arch): pass recipe = LibffiRecipe() - diff --git a/recipes/hostlibffi/libffi-xcode10.patch b/recipes/hostlibffi/libffi-xcode10.patch new file mode 100644 index 0000000..afe5058 --- /dev/null +++ b/recipes/hostlibffi/libffi-xcode10.patch @@ -0,0 +1,391 @@ +--- libffi-3.2.1.old/generate-darwin-source-and-headers.py 2018-10-26 17:08:07.000000000 +0200 ++++ libffi-3.2.1/generate-darwin-source-and-headers.py 2018-10-26 17:08:50.000000000 +0200 +@@ -174,23 +174,23 @@ + + if generate_ios: + make_tramp() +- copy_src_platform_files(simulator_platform) ++ #copy_src_platform_files(simulator_platform) + copy_src_platform_files(simulator64_platform) + copy_src_platform_files(device_platform) + copy_src_platform_files(device64_platform) + if generate_osx: +- copy_src_platform_files(desktop32_platform) ++ #copy_src_platform_files(desktop32_platform) + copy_src_platform_files(desktop64_platform) + + platform_headers = collections.defaultdict(set) + + if generate_ios: +- build_target(simulator_platform, platform_headers) ++ #build_target(simulator_platform, platform_headers) + build_target(simulator64_platform, platform_headers) + build_target(device_platform, platform_headers) + build_target(device64_platform, platform_headers) + if generate_osx: +- build_target(desktop32_platform, platform_headers) ++ #build_target(desktop32_platform, platform_headers) + build_target(desktop64_platform, platform_headers) + + mkdir_p('darwin_common/include') +--- libffi-3.2.1.old/configure 2014-11-12 12:59:57.000000000 +0100 ++++ libffi-3.2.1/configure 2018-10-26 09:02:12.000000000 +0200 +@@ -18725,11 +18725,11 @@ + toolexecdir="${libdir}"/gcc-lib/'$(target_alias)' + toolexeclibdir="${libdir}" + fi +- multi_os_directory=`$CC $CFLAGS -print-multi-os-directory` +- case $multi_os_directory in +- .) ;; # Avoid trailing /. +- ../*) toolexeclibdir=$toolexeclibdir/$multi_os_directory ;; +- esac ++ # multi_os_directory=`$CC $CFLAGS -print-multi-os-directory` ++ # case $multi_os_directory in ++ # .) ;; # Avoid trailing /. ++ # ../*) toolexeclibdir=$toolexeclibdir/$multi_os_directory ;; ++ # esac + + else + toolexeclibdir="${libdir}" +--- libffi-3.2.1.old/configure.ac 2014-11-12 12:56:51.000000000 +0100 ++++ libffi-3.2.1/configure.ac 2018-10-26 09:00:50.000000000 +0200 +@@ -601,11 +601,11 @@ + toolexecdir="${libdir}"/gcc-lib/'$(target_alias)' + toolexeclibdir="${libdir}" + fi +- multi_os_directory=`$CC $CFLAGS -print-multi-os-directory` +- case $multi_os_directory in +- .) ;; # Avoid trailing /. +- ../*) toolexeclibdir=$toolexeclibdir/$multi_os_directory ;; +- esac ++ # multi_os_directory=`$CC $CFLAGS -print-multi-os-directory` ++ # case $multi_os_directory in ++ # .) ;; # Avoid trailing /. ++ # ../*) toolexeclibdir=$toolexeclibdir/$multi_os_directory ;; ++ # esac + AC_SUBST(toolexecdir) + else + toolexeclibdir="${libdir}" +--- libffi-3.2.1.old/libffi.xcodeproj/project.pbxproj 2018-10-26 17:31:30.000000000 +0200 ++++ libffi-3.2.1/libffi.xcodeproj/project.pbxproj 2018-10-26 17:30:17.000000000 +0200 +@@ -24,20 +24,11 @@ + DBFA7179187F1D9B00A76262 /* ffi_armv7.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA716F187F1D9B00A76262 /* ffi_armv7.c */; }; + DBFA717A187F1D9B00A76262 /* sysv_armv7.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7170187F1D9B00A76262 /* sysv_armv7.S */; }; + DBFA717B187F1D9B00A76262 /* trampoline_armv7.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7171187F1D9B00A76262 /* trampoline_armv7.S */; }; +- DBFA717C187F1D9B00A76262 /* darwin64_x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7173187F1D9B00A76262 /* darwin64_x86_64.S */; }; +- DBFA717D187F1D9B00A76262 /* darwin_i386.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7174187F1D9B00A76262 /* darwin_i386.S */; }; +- DBFA717E187F1D9B00A76262 /* ffi64_x86_64.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7175187F1D9B00A76262 /* ffi64_x86_64.c */; }; +- DBFA717F187F1D9B00A76262 /* ffi_i386.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7176187F1D9B00A76262 /* ffi_i386.c */; }; +- DBFA718E187F1DA100A76262 /* ffi_i386.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA7182187F1DA100A76262 /* ffi_i386.h */; settings = {ATTRIBUTES = (Private, ); }; }; + DBFA718F187F1DA100A76262 /* ffi_x86_64.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA7183187F1DA100A76262 /* ffi_x86_64.h */; settings = {ATTRIBUTES = (Private, ); }; }; +- DBFA7190187F1DA100A76262 /* fficonfig_i386.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA7184187F1DA100A76262 /* fficonfig_i386.h */; settings = {ATTRIBUTES = (Private, ); }; }; + DBFA7191187F1DA100A76262 /* fficonfig_x86_64.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA7185187F1DA100A76262 /* fficonfig_x86_64.h */; settings = {ATTRIBUTES = (Private, ); }; }; +- DBFA7192187F1DA100A76262 /* ffitarget_i386.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA7186187F1DA100A76262 /* ffitarget_i386.h */; settings = {ATTRIBUTES = (Private, ); }; }; + DBFA7193187F1DA100A76262 /* ffitarget_x86_64.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA7187187F1DA100A76262 /* ffitarget_x86_64.h */; settings = {ATTRIBUTES = (Private, ); }; }; + DBFA7194187F1DA100A76262 /* darwin64_x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA718A187F1DA100A76262 /* darwin64_x86_64.S */; }; +- DBFA7195187F1DA100A76262 /* darwin_i386.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA718B187F1DA100A76262 /* darwin_i386.S */; }; + DBFA7196187F1DA100A76262 /* ffi64_x86_64.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA718C187F1DA100A76262 /* ffi64_x86_64.c */; }; +- DBFA7197187F1DA100A76262 /* ffi_i386.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA718D187F1DA100A76262 /* ffi_i386.c */; }; + /* End PBXBuildFile section */ + + /* Begin PBXCopyFilesBuildPhase section */ +@@ -81,20 +72,11 @@ + DBFA716F187F1D9B00A76262 /* ffi_armv7.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi_armv7.c; sourceTree = ""; }; + DBFA7170187F1D9B00A76262 /* sysv_armv7.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = sysv_armv7.S; sourceTree = ""; }; + DBFA7171187F1D9B00A76262 /* trampoline_armv7.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = trampoline_armv7.S; sourceTree = ""; }; +- DBFA7173187F1D9B00A76262 /* darwin64_x86_64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = darwin64_x86_64.S; sourceTree = ""; }; +- DBFA7174187F1D9B00A76262 /* darwin_i386.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = darwin_i386.S; sourceTree = ""; }; +- DBFA7175187F1D9B00A76262 /* ffi64_x86_64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi64_x86_64.c; sourceTree = ""; }; +- DBFA7176187F1D9B00A76262 /* ffi_i386.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi_i386.c; sourceTree = ""; }; +- DBFA7182187F1DA100A76262 /* ffi_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_i386.h; sourceTree = ""; }; + DBFA7183187F1DA100A76262 /* ffi_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_x86_64.h; sourceTree = ""; }; +- DBFA7184187F1DA100A76262 /* fficonfig_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig_i386.h; sourceTree = ""; }; + DBFA7185187F1DA100A76262 /* fficonfig_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig_x86_64.h; sourceTree = ""; }; +- DBFA7186187F1DA100A76262 /* ffitarget_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_i386.h; sourceTree = ""; }; + DBFA7187187F1DA100A76262 /* ffitarget_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_x86_64.h; sourceTree = ""; }; + DBFA718A187F1DA100A76262 /* darwin64_x86_64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = darwin64_x86_64.S; sourceTree = ""; }; +- DBFA718B187F1DA100A76262 /* darwin_i386.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = darwin_i386.S; sourceTree = ""; }; + DBFA718C187F1DA100A76262 /* ffi64_x86_64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi64_x86_64.c; sourceTree = ""; }; +- DBFA718D187F1DA100A76262 /* ffi_i386.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi_i386.c; sourceTree = ""; }; + /* End PBXFileReference section */ + + /* Begin PBXGroup section */ +@@ -182,7 +164,6 @@ + children = ( + DBFA716B187F1D9B00A76262 /* aarch64 */, + DBFA716E187F1D9B00A76262 /* arm */, +- DBFA7172187F1D9B00A76262 /* x86 */, + ); + path = src; + sourceTree = ""; +@@ -206,17 +187,6 @@ + path = arm; + sourceTree = ""; + }; +- DBFA7172187F1D9B00A76262 /* x86 */ = { +- isa = PBXGroup; +- children = ( +- DBFA7173187F1D9B00A76262 /* darwin64_x86_64.S */, +- DBFA7174187F1D9B00A76262 /* darwin_i386.S */, +- DBFA7175187F1D9B00A76262 /* ffi64_x86_64.c */, +- DBFA7176187F1D9B00A76262 /* ffi_i386.c */, +- ); +- path = x86; +- sourceTree = ""; +- }; + DBFA7180187F1DA100A76262 /* darwin_osx */ = { + isa = PBXGroup; + children = ( +@@ -229,11 +199,8 @@ + DBFA7181187F1DA100A76262 /* include */ = { + isa = PBXGroup; + children = ( +- DBFA7182187F1DA100A76262 /* ffi_i386.h */, + DBFA7183187F1DA100A76262 /* ffi_x86_64.h */, +- DBFA7184187F1DA100A76262 /* fficonfig_i386.h */, + DBFA7185187F1DA100A76262 /* fficonfig_x86_64.h */, +- DBFA7186187F1DA100A76262 /* ffitarget_i386.h */, + DBFA7187187F1DA100A76262 /* ffitarget_x86_64.h */, + ); + path = include; +@@ -251,9 +218,7 @@ + isa = PBXGroup; + children = ( + DBFA718A187F1DA100A76262 /* darwin64_x86_64.S */, +- DBFA718B187F1DA100A76262 /* darwin_i386.S */, + DBFA718C187F1DA100A76262 /* ffi64_x86_64.c */, +- DBFA718D187F1DA100A76262 /* ffi_i386.c */, + ); + path = x86; + sourceTree = ""; +@@ -269,12 +234,9 @@ + DBFA714D187F1D8600A76262 /* ffitarget.h in Headers */, + DBFA714B187F1D8600A76262 /* ffi_common.h in Headers */, + DBFA718F187F1DA100A76262 /* ffi_x86_64.h in Headers */, +- DBFA718E187F1DA100A76262 /* ffi_i386.h in Headers */, +- DBFA7192187F1DA100A76262 /* ffitarget_i386.h in Headers */, + DBFA7193187F1DA100A76262 /* ffitarget_x86_64.h in Headers */, + DBFA714C187F1D8600A76262 /* fficonfig.h in Headers */, + DBFA7191187F1DA100A76262 /* fficonfig_x86_64.h in Headers */, +- DBFA7190187F1DA100A76262 /* fficonfig_i386.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +@@ -321,7 +283,7 @@ + DB13B15C1849DEB70010F42D /* Project object */ = { + isa = PBXProject; + attributes = { +- LastUpgradeCheck = 0510; ++ LastUpgradeCheck = 1000; + }; + buildConfigurationList = DB13B15F1849DEB70010F42D /* Build configuration list for PBXProject "libffi" */; + compatibilityVersion = "Xcode 3.2"; +@@ -366,7 +328,7 @@ + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; +- shellScript = "/usr/bin/python generate-darwin-source-and-headers.py --only-osx"; ++ shellScript = "/usr/bin/python generate-darwin-source-and-headers.py --only-osx\n"; + }; + /* End PBXShellScriptBuildPhase section */ + +@@ -375,17 +337,13 @@ + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( +- DBFA717E187F1D9B00A76262 /* ffi64_x86_64.c in Sources */, + DBFA7179187F1D9B00A76262 /* ffi_armv7.c in Sources */, + DBFA717B187F1D9B00A76262 /* trampoline_armv7.S in Sources */, + DBFA714E187F1D8600A76262 /* closures.c in Sources */, + DBFA717A187F1D9B00A76262 /* sysv_armv7.S in Sources */, +- DBFA717D187F1D9B00A76262 /* darwin_i386.S in Sources */, + DBFA7156187F1D8600A76262 /* prep_cif.c in Sources */, +- DBFA717F187F1D9B00A76262 /* ffi_i386.c in Sources */, + DBFA7158187F1D8600A76262 /* raw_api.c in Sources */, + DBFA7178187F1D9B00A76262 /* sysv_arm64.S in Sources */, +- DBFA717C187F1D9B00A76262 /* darwin64_x86_64.S in Sources */, + DBFA715A187F1D8600A76262 /* types.c in Sources */, + DBFA7177187F1D9B00A76262 /* ffi_arm64.c in Sources */, + ); +@@ -396,9 +354,7 @@ + buildActionMask = 2147483647; + files = ( + DBFA7196187F1DA100A76262 /* ffi64_x86_64.c in Sources */, +- DBFA7195187F1DA100A76262 /* darwin_i386.S in Sources */, + DBFA7157187F1D8600A76262 /* prep_cif.c in Sources */, +- DBFA7197187F1DA100A76262 /* ffi_i386.c in Sources */, + DBFA715B187F1D8600A76262 /* types.c in Sources */, + DBFA7159187F1D8600A76262 /* raw_api.c in Sources */, + DBFA714F187F1D8600A76262 /* closures.c in Sources */, +@@ -412,21 +368,74 @@ + DB13B1601849DEB70010F42D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { ++ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; ++ CLANG_WARN_BOOL_CONVERSION = YES; ++ CLANG_WARN_COMMA = YES; ++ CLANG_WARN_CONSTANT_CONVERSION = YES; ++ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; ++ CLANG_WARN_EMPTY_BODY = YES; ++ CLANG_WARN_ENUM_CONVERSION = YES; ++ CLANG_WARN_INFINITE_RECURSION = YES; ++ CLANG_WARN_INT_CONVERSION = YES; ++ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; ++ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; ++ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; ++ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; ++ CLANG_WARN_STRICT_PROTOTYPES = YES; ++ CLANG_WARN_SUSPICIOUS_MOVE = YES; ++ CLANG_WARN_UNREACHABLE_CODE = YES; ++ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; ++ ENABLE_STRICT_OBJC_MSGSEND = YES; ++ ENABLE_TESTABILITY = YES; ++ GCC_NO_COMMON_BLOCKS = YES; ++ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; ++ GCC_WARN_ABOUT_RETURN_TYPE = YES; ++ GCC_WARN_UNDECLARED_SELECTOR = YES; ++ GCC_WARN_UNINITIALIZED_AUTOS = YES; ++ GCC_WARN_UNUSED_FUNCTION = YES; ++ GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + darwin_common/include, + ); + ONLY_ACTIVE_ARCH = YES; ++ VALID_ARCHS = x86_64; + }; + name = Debug; + }; + DB13B1611849DEB70010F42D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { ++ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; ++ CLANG_WARN_BOOL_CONVERSION = YES; ++ CLANG_WARN_COMMA = YES; ++ CLANG_WARN_CONSTANT_CONVERSION = YES; ++ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; ++ CLANG_WARN_EMPTY_BODY = YES; ++ CLANG_WARN_ENUM_CONVERSION = YES; ++ CLANG_WARN_INFINITE_RECURSION = YES; ++ CLANG_WARN_INT_CONVERSION = YES; ++ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; ++ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; ++ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; ++ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; ++ CLANG_WARN_STRICT_PROTOTYPES = YES; ++ CLANG_WARN_SUSPICIOUS_MOVE = YES; ++ CLANG_WARN_UNREACHABLE_CODE = YES; ++ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; ++ ENABLE_STRICT_OBJC_MSGSEND = YES; ++ GCC_NO_COMMON_BLOCKS = YES; ++ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; ++ GCC_WARN_ABOUT_RETURN_TYPE = YES; ++ GCC_WARN_UNDECLARED_SELECTOR = YES; ++ GCC_WARN_UNINITIALIZED_AUTOS = YES; ++ GCC_WARN_UNUSED_FUNCTION = YES; ++ GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + darwin_common/include, + ); ++ VALID_ARCHS = x86_64; + }; + name = Release; + }; +@@ -434,7 +443,6 @@ + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; +- ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; +@@ -467,7 +475,7 @@ + "$(inherited)", + darwin_ios/include, + ); +- IPHONEOS_DEPLOYMENT_TARGET = 5.0; ++ IPHONEOS_DEPLOYMENT_TARGET = 8.0; + "IPHONEOS_DEPLOYMENT_TARGET[arch=arm64]" = 7.0; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = ffi; +@@ -480,7 +488,6 @@ + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; +- ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; +@@ -507,7 +514,7 @@ + "$(inherited)", + darwin_ios/include, + ); +- IPHONEOS_DEPLOYMENT_TARGET = 5.0; ++ IPHONEOS_DEPLOYMENT_TARGET = 8.0; + "IPHONEOS_DEPLOYMENT_TARGET[arch=arm64]" = 7.0; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = ffi; +--- libffi-3.2.1.old/libffi.xcodeproj/project.pbxproj.orig 2018-10-26 17:31:30.000000000 +0200 ++++ libffi-3.2.1/libffi.xcodeproj/project.pbxproj.orig 2018-10-26 17:27:16.000000000 +0200 +@@ -54,7 +54,7 @@ + + /* Begin PBXFileReference section */ + DB13B1661849DF1E0010F42D /* libffi.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libffi.a; sourceTree = BUILT_PRODUCTS_DIR; }; +- DB13B1911849DF510010F42D /* ffi.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = ffi.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; ++ DB13B1911849DF510010F42D /* libffi.a */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libffi.a; sourceTree = BUILT_PRODUCTS_DIR; }; + DBFA713E187F1D8600A76262 /* ffi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi.h; sourceTree = ""; }; + DBFA713F187F1D8600A76262 /* ffi_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_common.h; sourceTree = ""; }; + DBFA7140187F1D8600A76262 /* fficonfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig.h; sourceTree = ""; }; +@@ -112,7 +112,7 @@ + isa = PBXGroup; + children = ( + DB13B1661849DF1E0010F42D /* libffi.a */, +- DB13B1911849DF510010F42D /* ffi.dylib */, ++ DB13B1911849DF510010F42D /* libffi.a */, + ); + name = Products; + sourceTree = ""; +@@ -312,7 +312,7 @@ + ); + name = "libffi-Mac"; + productName = ffi; +- productReference = DB13B1911849DF510010F42D /* ffi.dylib */; ++ productReference = DB13B1911849DF510010F42D /* libffi.a */; + productType = "com.apple.product-type.library.dynamic"; + }; + /* End PBXNativeTarget section */ +@@ -535,6 +535,7 @@ + COPY_PHASE_STRIP = NO; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; ++ EXECUTABLE_EXTENSION = a; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; +@@ -558,7 +559,7 @@ + MACOSX_DEPLOYMENT_TARGET = 10.6; + ONLY_ACTIVE_ARCH = YES; + OTHER_LDFLAGS = "-Wl,-no_compact_unwind"; +- PRODUCT_NAME = ffi; ++ PRODUCT_NAME = libffi; + SDKROOT = macosx; + }; + name = Debug; +@@ -583,6 +584,7 @@ + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + ENABLE_NS_ASSERTIONS = NO; ++ EXECUTABLE_EXTENSION = a; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; +@@ -598,7 +600,7 @@ + MACH_O_TYPE = staticlib; + MACOSX_DEPLOYMENT_TARGET = 10.6; + OTHER_LDFLAGS = "-Wl,-no_compact_unwind"; +- PRODUCT_NAME = ffi; ++ PRODUCT_NAME = libffi; + SDKROOT = macosx; + }; + name = Release; diff --git a/toolchain.py b/toolchain.py index 4fd4100..b34b5ae 100755 --- a/toolchain.py +++ b/toolchain.py @@ -327,7 +327,7 @@ class Context(object): self.install_dir = "{}/dist/root".format(self.root_dir) self.include_dir = "{}/dist/include".format(self.root_dir) self.archs = ( - ArchSimulator(self), + # ArchSimulator(self), Arch64Simulator(self), ArchIOS(self), Arch64IOS(self)) From 97a5e399bf5a2bb2bcb68b17c9255f9efa764cc5 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Sat, 27 Oct 2018 18:51:07 +0200 Subject: [PATCH 12/42] fixes libffi for xcode 10 --- recipes/libffi/__init__.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/recipes/libffi/__init__.py b/recipes/libffi/__init__.py index d97f3f1..a24bc00 100644 --- a/recipes/libffi/__init__.py +++ b/recipes/libffi/__init__.py @@ -1,5 +1,6 @@ from toolchain import Recipe, shprint import sh +from os.path import exists class LibffiRecipe(Recipe): @@ -9,20 +10,27 @@ class LibffiRecipe(Recipe): library = "build/Release-{arch.sdk}/libffi.a" include_per_arch = True include_dir = "build_{arch.sdk}-{arch.arch}/include" + archs = ["x86_64", "armv7", "arm64"] def prebuild_arch(self, arch): if self.has_marker("patched"): return - # necessary as it doesn't compile with XCode 6.0. If we use 5.1.1, the - # compiler for i386 is not working. + # XCode 10 minimum is 8.0 now. shprint(sh.sed, "-i.bak", - "s/-miphoneos-version-min=5.1.1/-miphoneos-version-min=6.0/g", + "s/-miphoneos-version-min=5.1.1/-miphoneos-version-min=8.0/g", "generate-darwin-source-and-headers.py") self.apply_patch("fix-win32-unreferenced-symbol.patch") self.set_marker("patched") def build_arch(self, arch): + if exists("generate-darwin-source-and-headers.py"): + shprint( + sh.mv, + "generate-darwin-source-and-headers.py", + "_generate-darwin-source-and-headers.py") + shprint(sh.touch, "generate-darwin-source-and-headers.py") + shprint(sh.python2, "_generate-darwin-source-and-headers.py", "--only-ios") shprint(sh.xcodebuild, self.ctx.concurrent_xcodebuild, "ONLY_ACTIVE_ARCH=NO", "ARCHS={}".format(arch.arch), From b73c5209239a62a8a22ecd3eb53f38bc09fa8e69 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Sun, 28 Oct 2018 12:01:15 +0100 Subject: [PATCH 13/42] put CFLAGS into CC to prevent issue during ./configure. ref #301 --- toolchain.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/toolchain.py b/toolchain.py index b34b5ae..302452c 100755 --- a/toolchain.py +++ b/toolchain.py @@ -146,11 +146,24 @@ class Arch(object): env = {} ccache = sh.which('ccache') cc = sh.xcrun("-find", "-sdk", self.sdk, "clang").strip() + cxx = sh.xcrun("-find", "-sdk", self.sdk, "clang++").strip() + + # we put the flags in CC / CXX as sometimes the ./configure test + # with the preprocessor (aka CC -E) without CFLAGS, which fails for + # cross compiled projects + flags = " ".join([ + "--sysroot", self.sysroot, + "-arch", self.arch, + "-pipe", "-no-cpp-precomp", + ]) + cc += " " + flags + cxx += " " + flags if ccache: ccache = ccache.strip() use_ccache = environ.get("USE_CCACHE", "1") if use_ccache != '1': env["CC"] = cc + env["CXX"] = cxx else: if not self._ccsh: self._ccsh = ccsh = sh.mktemp().strip() @@ -158,11 +171,17 @@ class Arch(object): f.write('#!/bin/sh\n') f.write(ccache + ' ' + cc + ' "$@"\n') sh.chmod('+x', ccsh) + self._cxxsh = cxxsh = sh.mktemp().strip() + with open(cxxsh, 'w') as f: + f.write('#!/bin/sh\n') + f.write(ccache + ' ' + cxx + ' "$@"\n') + sh.chmod('+x', cxxsh) else: ccsh = self._ccsh env["USE_CCACHE"] = '1' env["CCACHE"] = ccache env["CC"] = ccsh + env["CXX"] = cxxsh env.update({k: v for k, v in environ.items() if k.startswith('CCACHE_')}) env.setdefault('CCACHE_MAXSIZE', '10G') @@ -171,6 +190,7 @@ class Arch(object): 'include_file_mtime,include_file_ctime,file_stat_matches')) else: env["CC"] = cc + env["CXX"] = cxx env["AR"] = sh.xcrun("-find", "-sdk", self.sdk, "ar").strip() env["LD"] = sh.xcrun("-find", "-sdk", self.sdk, "ld").strip() env["OTHER_CFLAGS"] = " ".join(include_dirs) @@ -178,11 +198,6 @@ class Arch(object): "-L{}/{}".format(self.ctx.dist_dir, "lib"), ]) env["CFLAGS"] = " ".join([ - "-arch", self.arch, - "-pipe", "-no-cpp-precomp", - "--sysroot", self.sysroot, - #"-I{}/common".format(self.ctx.include_dir), - #"-I{}/{}".format(self.ctx.include_dir, self.arch), "-O3", self.version_min ] + include_dirs) From 6ffd07ab06a3291f233ef02ebe68ba4a172cd5ca Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Sun, 28 Oct 2018 12:14:35 +0100 Subject: [PATCH 14/42] print recipes in order --- toolchain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolchain.py b/toolchain.py index 302452c..d91c792 100755 --- a/toolchain.py +++ b/toolchain.py @@ -847,7 +847,7 @@ class Recipe(object): @classmethod def list_recipes(cls): recipes_dir = join(dirname(__file__), "recipes") - for name in listdir(recipes_dir): + for name in sorted(listdir(recipes_dir)): fn = join(recipes_dir, name) if isdir(fn): yield name From 3f262e6549488c640a2b9a0727afd1d449ed1955 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Sun, 28 Oct 2018 13:18:54 +0100 Subject: [PATCH 15/42] fix hostpython openssl inclusion, and cxxsh --- recipes/hostpython/__init__.py | 1 + toolchain.py | 1 + 2 files changed, 2 insertions(+) diff --git a/recipes/hostpython/__init__.py b/recipes/hostpython/__init__.py index 2645fce..3281a00 100644 --- a/recipes/hostpython/__init__.py +++ b/recipes/hostpython/__init__.py @@ -66,6 +66,7 @@ class HostpythonRecipe(Recipe): ]) if "openssl.build_all" in self.ctx.state: + build_env["LDFLAGS"] += " -L{}".format(join(self.ctx.dist_dir, "lib")) build_env["CFLAGS"] += " -I{}".format(join(self.ctx.dist_dir, "include", "x86_64", "openssl")) diff --git a/toolchain.py b/toolchain.py index d91c792..c6b4275 100755 --- a/toolchain.py +++ b/toolchain.py @@ -178,6 +178,7 @@ class Arch(object): sh.chmod('+x', cxxsh) else: ccsh = self._ccsh + cxxsh = self._cxxsh env["USE_CCACHE"] = '1' env["CCACHE"] = ccache env["CC"] = ccsh From 98c487fd076daf9cd0e7ee32a5620679d07cf0d8 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Sun, 28 Oct 2018 16:24:11 +0100 Subject: [PATCH 16/42] update README.rst --- README.rst | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/README.rst b/README.rst index 4233f5d..99d34e1 100644 --- a/README.rst +++ b/README.rst @@ -4,13 +4,12 @@ Kivy for iOS This toolchain is designed to compile the necessary libraries for iOS to run your application and manage the creation of the Xcode project. -Currently, we do not provide any binary distributions of this toolchain, but we -aim to. Until then, you do need to compile it at least once before creating -your Xcode project. +We do not provide any binary distributions of this toolchain. +You do need to compile it at least once before creating your Xcode project. The toolchain supports: -- iPhone Simulator (x86 and x86_64) +- iPhone Simulator (x86_64) - iPhone / iOS (armv7 and arm64) These recipes are not ported to the new toolchain yet: @@ -23,7 +22,11 @@ Requirements Currently, the toolchain requires a few tools for compilation. You will need: -#. Xcode 6 or above, with an iOS SDK and command line tools installed:: +#. Ensure you have the right dependencies installed:: + + pip install -r requirements.txt + +#. Xcode 10 or above, with an iOS SDK and command line tools installed:: xcode-select --install @@ -32,10 +35,10 @@ Currently, the toolchain requires a few tools for compilation. You will need: brew install autoconf automake libtool pkg-config brew link libtool -#. Install Cython (0.23):: +#. Install Cython (0.25.2):: # pip method if available (sudo might be needed.) - pip install cython==0.23 + pip install cython==0.25.2 Using the toolchain @@ -202,7 +205,7 @@ FAQ Fatal error: "stdio.h" file not found You need to install the Command line tools: `xcode-select --install` - + You must build with bitcode disabled (Xcode setting ENABLE_BITCODE should be No). We don't support bitcode. You need to go to the project setting, and disable bitcode. @@ -214,11 +217,10 @@ If you need assistance, you can ask for help on our mailing list: * User Group : https://groups.google.com/group/kivy-users * Email : kivy-users@googlegroups.com -We also have an IRC channel: +We also have a Discord channel: -* Server : irc.freenode.net -* Port : 6667, 6697 (SSL only) -* Channel : #kivy +* Server : https://chat.kivy.org +* Channel : #support Contributing ------------ @@ -233,11 +235,10 @@ discussions about developing the Kivy framework and its sister projects: * Dev Group : https://groups.google.com/group/kivy-dev * Email : kivy-dev@googlegroups.com -IRC channel: +Discord channel: -* Server : irc.freenode.net -* Port : 6667, 6697 (SSL only) -* Channel : #kivy-dev +* Server : https://chat.kivy.org +* Channel : #dev License ------- From 8e1960f28cb03ea1ce8d98b6dafb56b059248272 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Sun, 28 Oct 2018 16:24:54 +0100 Subject: [PATCH 17/42] update xcodeproj generation, use latest mod_pbxproj project to be able to handle tbd files, and fixes issues about code signing when the frameworks are added in Embed Frameworks. --- requirements.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..946b8cd --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +pbxproj==2.5.1 From 5311f0c09884ea9e201bb9f177f0e97fe8508540 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Sun, 28 Oct 2018 22:07:10 +0100 Subject: [PATCH 18/42] fixes requirements, remove mod_pbxproj and use up to date mod_pbxproj to handle tbd files --- toolchain.py | 37 +- tools/external/mod_pbxproj.py | 1578 ----------------- .../project.pbxproj | 6 +- 3 files changed, 27 insertions(+), 1594 deletions(-) delete mode 100755 tools/external/mod_pbxproj.py diff --git a/toolchain.py b/toolchain.py index c6b4275..80a3961 100755 --- a/toolchain.py +++ b/toolchain.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ Tool for compiling iOS toolchain ================================ @@ -22,7 +22,13 @@ try: from urllib.request import FancyURLopener, urlcleanup except ImportError: from urllib import FancyURLopener, urlcleanup - +try: + from pbxproj import XcodeProject + from pbxproj.pbxextensions.ProjectFiles import FileOptions +except ImportError: + print("ERROR: pbxproj requirements is missing") + print("To install: pip install -r requirements.txt") + sys.exit(0) curdir = dirname(__file__) sys.path.insert(0, join(curdir, "tools", "external")) @@ -1062,39 +1068,42 @@ def update_pbxproj(filename): print("-" * 70) print("Analysis of {}".format(filename)) - from mod_pbxproj import XcodeProject - project = XcodeProject.Load(filename) + project = XcodeProject.load(filename) sysroot = sh.xcrun("--sdk", "iphonesimulator", "--show-sdk-path").strip() 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) for framework in pbx_frameworks: framework_name = "{}.framework".format(framework) if framework_name in frameworks: - print("Ensure {} is in the project (local)".format(framework)) + print("Ensure {} is in the project (pbx_frameworks, local)".format(framework)) f_path = join(ctx.dist_dir, "frameworks", framework_name) else: - print("Ensure {} is in the project (system)".format(framework)) + print("Ensure {} is in the project (pbx_frameworks, system)".format(framework)) f_path = join(sysroot, "System", "Library", "Frameworks", "{}.framework".format(framework)) - project.add_file_if_doesnt_exist(f_path, parent=group, tree="DEVELOPER_DIR") + project.add_file(f_path, parent=group, tree="DEVELOPER_DIR", + force=False, file_options=file_options) for library in pbx_libraries: - print("Ensure {} is in the project".format(library)) + print("Ensure {} is in the project (pbx_libraries, dylib+tbd)".format(library)) f_path = join(sysroot, "usr", "lib", "{}.dylib".format(library)) - project.add_file_if_doesnt_exist(f_path, parent=group, tree="DEVELOPER_DIR") + project.add_file(f_path, parent=group, tree="DEVELOPER_DIR", force=False) + f_path = join(sysroot, "usr", "lib", + "{}.tbd".format(library)) + project.add_file(f_path, parent=group, tree="DEVELOPER_DIR", force=False) for library in libraries: - print("Ensure {} is in the project".format(library)) - project.add_file_if_doesnt_exist(library, parent=group) + print("Ensure {} is in the project (libraries)".format(library)) + project.add_file(library, parent=group, force=False) for name in sources: print("Ensure {} sources are used".format(name)) fn = join(ctx.dist_dir, "sources", name) project.add_folder(fn, parent=g_classes) - if project.modified: - project.backup() - project.save() + project.backup() + project.save() if __name__ == "__main__": diff --git a/tools/external/mod_pbxproj.py b/tools/external/mod_pbxproj.py deleted file mode 100755 index ac4e15a..0000000 --- a/tools/external/mod_pbxproj.py +++ /dev/null @@ -1,1578 +0,0 @@ -# Copyright 2012 Calvin Rien -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# A pbxproj file is an OpenStep format plist -# {} represents dictionary of key=value pairs delimited by ; -# () represents list of values delimited by , -# file starts with a comment specifying the character type -# // !$*UTF8*$! - -# when adding a file to a project, create the PBXFileReference -# add the PBXFileReference's guid to a group -# create a PBXBuildFile with the PBXFileReference's guid -# add the PBXBuildFile to the appropriate build phase - -# when adding a header search path add -# HEADER_SEARCH_PATHS = "path/**"; -# to each XCBuildConfiguration object - -# Xcode4 will read either a OpenStep or XML plist. -# this script uses `plutil` to validate, read and write -# the pbxproj file. Plutil is available in OS X 10.2 and higher -# Plutil can't write OpenStep plists, so I save as XML - -import datetime -import json -import ntpath -import os -import re -import shutil -import subprocess -import uuid -import plistlib - -try: - from UserDict import IterableUserDict - from UserList import UserList - -except: - # python 3 support - from collections import UserDict as IterableUserDict - from collections import UserList - -try: - from plistlib import PlistWriter - -except: - # python 3 support - from plistlib import _PlistWriter as PlistWriter - basestring = str - -regex = '[a-zA-Z0-9\\._/-]*' - - -class PBXEncoder(json.JSONEncoder): - def default(self, obj): - """Tests the input object, obj, to encode as JSON.""" - - if isinstance(obj, (PBXList, PBXDict)): - return obj.data - - return json.JSONEncoder.default(self, obj) - - -class PBXDict(IterableUserDict): - def __init__(self, d=None): - if d: - d = dict([(PBXType.Convert(k), PBXType.Convert(v)) for k, v in d.items()]) - - IterableUserDict.__init__(self, d) - - def __setitem__(self, key, value): - IterableUserDict.__setitem__(self, PBXType.Convert(key), PBXType.Convert(value)) - - def remove(self, key): - self.data.pop(PBXType.Convert(key), None) - - -class PBXList(UserList): - def __init__(self, l=None): - if isinstance(l, basestring): - UserList.__init__(self) - self.add(l) - return - elif l: - l = [PBXType.Convert(v) for v in l] - - UserList.__init__(self, l) - - def add(self, value): - value = PBXType.Convert(value) - - if value in self.data: - return False - - self.data.append(value) - return True - - def remove(self, value): - value = PBXType.Convert(value) - - if value in self.data: - self.data.remove(value) - return True - return False - - def __setitem__(self, key, value): - UserList.__setitem__(self, PBXType.Convert(key), PBXType.Convert(value)) - - -class PBXType(PBXDict): - def __init__(self, d=None): - PBXDict.__init__(self, d) - - if 'isa' not in self: - self['isa'] = self.__class__.__name__ - self.id = None - - @staticmethod - def Convert(o): - if isinstance(o, list): - return PBXList(o) - elif isinstance(o, dict): - isa = o.get('isa') - - if not isa: - return PBXDict(o) - - cls = globals().get(isa) - - if cls and issubclass(cls, PBXType): - return cls(o) - - print('warning: unknown PBX type: %s' % isa) - return PBXDict(o) - else: - return o - - @staticmethod - def IsGuid(o): - return re.match('^[A-F0-9]{24}$', str(o)) - - @classmethod - def GenerateId(cls): - return ''.join(str(uuid.uuid4()).upper().split('-')[1:]) - - @classmethod - def Create(cls, *args, **kwargs): - return cls(*args, **kwargs) - - -class PBXFileReference(PBXType): - def __init__(self, d=None): - PBXType.__init__(self, d) - self.build_phase = None - - types = { - '.a': ('archive.ar', 'PBXFrameworksBuildPhase'), - '.app': ('wrapper.application', None), - '.s': ('sourcecode.asm', 'PBXSourcesBuildPhase'), - '.c': ('sourcecode.c.c', 'PBXSourcesBuildPhase'), - '.cpp': ('sourcecode.cpp.cpp', 'PBXSourcesBuildPhase'), - '.framework': ('wrapper.framework', 'PBXFrameworksBuildPhase'), - '.h': ('sourcecode.c.h', None), - '.hpp': ('sourcecode.c.h', None), - '.swift': ('sourcecode.swift', None), - '.icns': ('image.icns', 'PBXResourcesBuildPhase'), - '.m': ('sourcecode.c.objc', 'PBXSourcesBuildPhase'), - '.j': ('sourcecode.c.objc', 'PBXSourcesBuildPhase'), - '.mm': ('sourcecode.cpp.objcpp', 'PBXSourcesBuildPhase'), - '.nib': ('wrapper.nib', 'PBXResourcesBuildPhase'), - '.plist': ('text.plist.xml', 'PBXResourcesBuildPhase'), - '.json': ('text.json', 'PBXResourcesBuildPhase'), - '.png': ('image.png', 'PBXResourcesBuildPhase'), - '.rtf': ('text.rtf', 'PBXResourcesBuildPhase'), - '.tiff': ('image.tiff', 'PBXResourcesBuildPhase'), - '.txt': ('text', 'PBXResourcesBuildPhase'), - '.xcodeproj': ('wrapper.pb-project', None), - '.xib': ('file.xib', 'PBXResourcesBuildPhase'), - '.strings': ('text.plist.strings', 'PBXResourcesBuildPhase'), - '.bundle': ('wrapper.plug-in', 'PBXResourcesBuildPhase'), - '.dylib': ('compiled.mach-o.dylib', 'PBXFrameworksBuildPhase') - } - - trees = [ - '', - '', - 'BUILT_PRODUCTS_DIR', - 'DEVELOPER_DIR', - 'SDKROOT', - 'SOURCE_ROOT', - ] - - def guess_file_type(self, ignore_unknown_type=False): - self.remove('explicitFileType') - self.remove('lastKnownFileType') - - ext = os.path.splitext(self.get('name', ''))[1] - if os.path.isdir(self.get('path')) and ext != '.framework' and ext != '.bundle': - f_type = 'folder' - build_phase = None - ext = '' - else: - f_type, build_phase = PBXFileReference.types.get(ext, ('?', 'PBXResourcesBuildPhase')) - - self['lastKnownFileType'] = f_type - self.build_phase = build_phase - - if f_type == '?' and not ignore_unknown_type: - print('unknown file extension: %s' % ext) - print('please add extension and Xcode type to PBXFileReference.types') - - return f_type - - def set_file_type(self, ft): - self.remove('explicitFileType') - self.remove('lastKnownFileType') - - self['explicitFileType'] = ft - - @classmethod - def Create(cls, os_path, tree='SOURCE_ROOT', ignore_unknown_type=False): - if tree not in cls.trees: - print('Not a valid sourceTree type: %s' % tree) - return None - - fr = cls() - fr.id = cls.GenerateId() - fr['path'] = os_path - fr['name'] = os.path.split(os_path)[1] - fr['sourceTree'] = '' if os.path.isabs(os_path) else tree - fr.guess_file_type(ignore_unknown_type=ignore_unknown_type) - - return fr - - -class PBXBuildFile(PBXType): - def set_weak_link(self, weak=False): - k_settings = 'settings' - k_attributes = 'ATTRIBUTES' - - s = self.get(k_settings) - - if not s: - if weak: - self[k_settings] = PBXDict({k_attributes: PBXList(['Weak'])}) - - return True - - atr = s.get(k_attributes) - - if not atr: - if weak: - atr = PBXList() - else: - return False - - if weak: - atr.add('Weak') - else: - atr.remove('Weak') - - self[k_settings][k_attributes] = atr - - return True - - def add_compiler_flag(self, flag): - k_settings = 'settings' - k_attributes = 'COMPILER_FLAGS' - - if k_settings not in self: - self[k_settings] = PBXDict() - - if k_attributes not in self[k_settings]: - self[k_settings][k_attributes] = flag - return True - - flags = self[k_settings][k_attributes].split(' ') - - if flag in flags: - return False - - flags.append(flag) - - self[k_settings][k_attributes] = ' '.join(flags) - - @classmethod - def Create(cls, file_ref, weak=False): - if isinstance(file_ref, PBXFileReference): - file_ref = file_ref.id - - bf = cls() - bf.id = cls.GenerateId() - bf['fileRef'] = file_ref - - if weak: - bf.set_weak_link(True) - - return bf - - -class PBXGroup(PBXType): - def add_child(self, ref): - if not isinstance(ref, PBXDict): - return None - - isa = ref.get('isa') - - if isa != 'PBXFileReference' and isa != 'PBXGroup': - return None - - if 'children' not in self: - self['children'] = PBXList() - - self['children'].add(ref.id) - - return ref.id - - def remove_child(self, id): - if 'children' not in self: - self['children'] = PBXList() - return - - if not PBXType.IsGuid(id): - id = id.id - - self['children'].remove(id) - - def has_child(self, id): - if 'children' not in self: - self['children'] = PBXList() - return False - - if not PBXType.IsGuid(id): - id = id.id - - return id in self['children'] - - def get_name(self): - path_name = os.path.split(self.get('path', ''))[1] - return self.get('name', path_name) - - @classmethod - def Create(cls, name, path=None, tree='SOURCE_ROOT'): - grp = cls() - grp.id = cls.GenerateId() - grp['name'] = name - grp['children'] = PBXList() - - if path: - grp['path'] = path - grp['sourceTree'] = tree - else: - grp['sourceTree'] = '' - - return grp - - -class PBXNativeTarget(PBXType): - pass - - -class PBXProject(PBXType): - pass - - -class PBXContainerItemProxy(PBXType): - pass - - -class PBXReferenceProxy(PBXType): - pass - - -class PBXVariantGroup(PBXType): - pass - - -class PBXTargetDependency(PBXType): - pass - - -class PBXAggregateTarget(PBXType): - pass - - -class PBXHeadersBuildPhase(PBXType): - pass - - -class PBXBuildPhase(PBXType): - def add_build_file(self, bf): - if bf.get('isa') != 'PBXBuildFile': - return False - - if 'files' not in self: - self['files'] = PBXList() - - self['files'].add(bf.id) - - return True - - def remove_build_file(self, id): - if 'files' not in self: - self['files'] = PBXList() - return - - self['files'].remove(id) - - def has_build_file(self, id): - if 'files' not in self: - self['files'] = PBXList() - return False - - if not PBXType.IsGuid(id): - id = id.id - - return id in self['files'] - - -class PBXFrameworksBuildPhase(PBXBuildPhase): - pass - - -class PBXResourcesBuildPhase(PBXBuildPhase): - pass - - -class PBXShellScriptBuildPhase(PBXBuildPhase): - @classmethod - def Create(cls, script, shell="/bin/sh", files=[], input_paths=[], output_paths=[], show_in_log = '0'): - bf = cls() - bf.id = cls.GenerateId() - bf['files'] = files - bf['inputPaths'] = input_paths - bf['outputPaths'] = output_paths - bf['runOnlyForDeploymentPostprocessing'] = '0'; - bf['shellPath'] = shell - bf['shellScript'] = script - bf['showEnvVarsInLog'] = show_in_log - - return bf - - -class PBXSourcesBuildPhase(PBXBuildPhase): - pass - - -class PBXCopyFilesBuildPhase(PBXBuildPhase): - pass - - -class XCBuildConfiguration(PBXType): - def add_search_paths(self, paths, base, key, recursive=True, escape=True): - modified = False - - if not isinstance(paths, list): - paths = [paths] - - if base not in self: - self[base] = PBXDict() - - for path in paths: - if recursive and not path.endswith('/**'): - path = os.path.join(path, '**') - - if key not in self[base]: - self[base][key] = PBXList() - elif isinstance(self[base][key], basestring): - self[base][key] = PBXList(self[base][key]) - - if escape: - if self[base][key].add('"%s"' % path): # '\\"%s\\"' % path - modified = True - else: - if self[base][key].add(path): # '\\"%s\\"' % path - modified = True - - return modified - - def add_header_search_paths(self, paths, recursive=True): - return self.add_search_paths(paths, 'buildSettings', 'HEADER_SEARCH_PATHS', recursive=recursive) - - def add_library_search_paths(self, paths, recursive=True): - return self.add_search_paths(paths, 'buildSettings', 'LIBRARY_SEARCH_PATHS', recursive=recursive) - - def add_framework_search_paths(self, paths, recursive=True): - return self.add_search_paths(paths, 'buildSettings', 'FRAMEWORK_SEARCH_PATHS', recursive=recursive) - - def add_other_cflags(self, flags): - return self.add_flag('OTHER_CFLAGS', flags) - - def add_other_ldflags(self, flags): - return self.add_flag('OTHER_LDFLAGS', flags) - - def add_flag(self, key, flags): - modified = False - base = 'buildSettings' - - if isinstance(flags, basestring): - flags = PBXList(flags) - - if base not in self: - self[base] = PBXDict() - - for flag in flags: - if key not in self[base]: - self[base][key] = PBXList() - elif isinstance(self[base][key], basestring): - self[base][key] = PBXList(self[base][key]) - - if self[base][key].add(flag): - self[base][key] = [e for e in self[base][key] if e] - modified = True - - return modified - - def remove_flag(self, key, flags): - modified = False - base = 'buildSettings' - - if isinstance(flags, basestring): - flags = PBXList(flags) - - if base in self: # there are flags, so we can "remove" something - for flag in flags: - if key not in self[base]: - return False - elif isinstance(self[base][key], basestring): - self[base][key] = PBXList(self[base][key]) - - if self[base][key].remove(flag): - self[base][key] = [e for e in self[base][key] if e] - modified = True - - if len(self[base][key]) == 0: - self[base].pop(key, None) - - return modified - - def remove_other_ldflags(self, flags): - return self.remove_flag('OTHER_LD_FLAGS', flags) - -class XCConfigurationList(PBXType): - pass - - -class XcodeProject(PBXDict): - plutil_path = 'plutil' - special_folders = ['.bundle', '.framework', '.xcodeproj'] - - def __init__(self, d=None, path=None): - if not path: - path = os.path.join(os.getcwd(), 'project.pbxproj') - - self.pbxproj_path = os.path.abspath(path) - self.source_root = os.path.abspath(os.path.join(os.path.split(path)[0], '..')) - - IterableUserDict.__init__(self, d) - - self.data = PBXDict(self.data) - self.objects = self.get('objects') - self.modified = False - - root_id = self.get('rootObject') - - if root_id: - self.root_object = self.objects[root_id] - root_group_id = self.root_object.get('mainGroup') - self.root_group = self.objects[root_group_id] - else: - print("error: project has no root object") - self.root_object = None - self.root_group = None - - try: - objectList = self.objects.iteritems() - - except: - # python 3 support - objectList = self.objects.items() - - for k, v in objectList: - v.id = k - - def add_other_cflags(self, flags): - build_configs = [b for b in self.objects.values() if b.get('isa') == 'XCBuildConfiguration'] - - for b in build_configs: - if b.add_other_cflags(flags): - self.modified = True - - def add_other_ldflags(self, flags): - build_configs = [b for b in self.objects.values() if b.get('isa') == 'XCBuildConfiguration'] - - for b in build_configs: - if b.add_other_ldflags(flags): - self.modified = True - - def remove_other_ldflags(self, flags): - build_configs = [b for b in self.objects.values() if b.get('isa') == 'XCBuildConfiguration'] - - for b in build_configs: - if b.remove_other_ldflags(flags): - self.modified = True - - def add_header_search_paths(self, paths, recursive=True): - build_configs = [b for b in self.objects.values() if b.get('isa') == 'XCBuildConfiguration'] - - for b in build_configs: - if b.add_header_search_paths(paths, recursive): - self.modified = True - - def add_framework_search_paths(self, paths, recursive=True): - build_configs = [b for b in self.objects.values() if b.get('isa') == 'XCBuildConfiguration'] - - for b in build_configs: - if b.add_framework_search_paths(paths, recursive): - self.modified = True - - def add_library_search_paths(self, paths, recursive=True): - build_configs = [b for b in self.objects.values() if b.get('isa') == 'XCBuildConfiguration'] - - for b in build_configs: - if b.add_library_search_paths(paths, recursive): - self.modified = True - - def add_flags(self, pairs, configuration='All'): - build_configs = [b for b in self.objects.values() if b.get('isa') == 'XCBuildConfiguration'] - - # iterate over all the pairs of configurations - for b in build_configs: - if configuration != "All" and b.get('name') != configuration : - continue - - for k in pairs: - if b.add_flag(k, pairs[k]): - self.modified = True - - def remove_flags(self, pairs, configuration='All'): - build_configs = [b for b in self.objects.values() if b.get('isa') == 'XCBuildConfiguration'] - - # iterate over all the pairs of configurations - for b in build_configs: - if configuration != "All" and b.get('name') != configuration : - continue - for k in pairs: - if b.remove_flag(k, pairs[k]): - self.modified = True - - def get_obj(self, id): - return self.objects.get(id) - - def get_ids(self): - return self.objects.keys() - - def get_files_by_os_path(self, os_path, tree='SOURCE_ROOT'): - files = [f for f in self.objects.values() if f.get('isa') == 'PBXFileReference' - and f.get('path') == os_path - and f.get('sourceTree') == tree] - - return files - - def get_files_by_name(self, name, parent=None): - if parent: - files = [f for f in self.objects.values() if f.get('isa') == 'PBXFileReference' - and f.get('name') == name - and parent.has_child(f)] - else: - files = [f for f in self.objects.values() if f.get('isa') == 'PBXFileReference' - and f.get('name') == name] - - return files - - def get_build_files(self, id): - files = [f for f in self.objects.values() if f.get('isa') == 'PBXBuildFile' - and f.get('fileRef') == id] - - return files - - def get_groups_by_name(self, name, parent=None): - if parent: - groups = [g for g in self.objects.values() if g.get('isa') == 'PBXGroup' - and g.get_name() == name - and parent.has_child(g)] - else: - groups = [g for g in self.objects.values() if g.get('isa') == 'PBXGroup' - and g.get_name() == name] - - return groups - - def get_or_create_group(self, name, path=None, parent=None): - if not name: - return None - - if not parent: - parent = self.root_group - elif not isinstance(parent, PBXGroup): - # assume it's an id - parent = self.objects.get(parent, self.root_group) - - groups = self.get_groups_by_name(name) - - for grp in groups: - if parent.has_child(grp.id): - return grp - - grp = PBXGroup.Create(name, path) - parent.add_child(grp) - - self.objects[grp.id] = grp - - self.modified = True - - return grp - - def get_groups_by_os_path(self, path): - path = os.path.abspath(path) - - groups = [g for g in self.objects.values() if g.get('isa') == 'PBXGroup' - and os.path.abspath(g.get('path', '/dev/null')) == path] - - return groups - - def get_build_phases(self, phase_name): - phases = [p for p in self.objects.values() if p.get('isa') == phase_name] - - return phases - - def get_relative_path(self, os_path): - return os.path.relpath(os_path, self.source_root) - - def verify_files(self, file_list, parent=None): - # returns list of files not in the current project. - if not file_list: - return [] - - if parent: - exists_list = [f.get('name') for f in self.objects.values() if f.get('isa') == 'PBXFileReference' and f.get('name') in file_list and parent.has_child(f)] - else: - exists_list = [f.get('name') for f in self.objects.values() if f.get('isa') == 'PBXFileReference' and f.get('name') in file_list] - - return set(file_list).difference(exists_list) - - def add_run_script(self, target, script=None): - result = [] - targets = [t for t in self.get_build_phases('PBXNativeTarget') + self.get_build_phases('PBXAggregateTarget') if t.get('name') == target] - if len(targets) != 0 : - script_phase = PBXShellScriptBuildPhase.Create(script) - for t in targets: - skip = False - for buildPhase in t['buildPhases']: - if self.objects[buildPhase].get('isa') == 'PBXShellScriptBuildPhase' and self.objects[buildPhase].get('shellScript') == script: - skip = True - - if not skip: - t['buildPhases'].add(script_phase.id) - self.objects[script_phase.id] = script_phase - result.append(script_phase) - - return result - - def add_run_script_all_targets(self, script=None): - result = [] - targets = self.get_build_phases('PBXNativeTarget') + self.get_build_phases('PBXAggregateTarget') - if len(targets) != 0 : - script_phase = PBXShellScriptBuildPhase.Create(script) - for t in targets: - skip = False - for buildPhase in t['buildPhases']: - if self.objects[buildPhase].get('isa') == 'PBXShellScriptBuildPhase' and self.objects[buildPhase].get('shellScript') == script: - skip = True - - if not skip: - t['buildPhases'].add(script_phase.id) - self.objects[script_phase.id] = script_phase - result.append(script_phase) - - return result - - def add_folder(self, os_path, parent=None, excludes=None, recursive=True, create_build_files=True): - if not os.path.isdir(os_path): - return [] - - if not excludes: - excludes = [] - - results = [] - - if not parent: - parent = self.root_group - elif not isinstance(parent, PBXGroup): - # assume it's an id - parent = self.objects.get(parent, self.root_group) - - path_dict = {os.path.split(os_path)[0]: parent} - special_list = [] - - for (grp_path, subdirs, files) in os.walk(os_path): - parent_folder, folder_name = os.path.split(grp_path) - parent = path_dict.get(parent_folder, parent) - - if [sp for sp in special_list if parent_folder.startswith(sp)]: - continue - - if folder_name.startswith('.'): - special_list.append(grp_path) - continue - - if os.path.splitext(grp_path)[1] in XcodeProject.special_folders: - # if this file has a special extension (bundle or framework mainly) treat it as a file - special_list.append(grp_path) - new_files = self.verify_files([folder_name], parent=parent) - - # Ignore this file if it is in excludes - if new_files and not [m for m in excludes if re.match(m, grp_path)]: - results.extend(self.add_file(grp_path, parent, create_build_files=create_build_files)) - - continue - - # create group - grp = self.get_or_create_group(folder_name, path=self.get_relative_path(grp_path), parent=parent) - path_dict[grp_path] = grp - - results.append(grp) - - file_dict = {} - - for f in files: - if f[0] == '.' or [m for m in excludes if re.match(m, f)]: - continue - - kwds = { - 'create_build_files': create_build_files, - 'parent': grp, - 'name': f - } - - f_path = os.path.join(grp_path, f) - file_dict[f_path] = kwds - - new_files = self.verify_files([n.get('name') for n in file_dict.values()], parent=grp) - add_files = [(k, v) for k, v in file_dict.items() if v.get('name') in new_files] - - for path, kwds in add_files: - kwds.pop('name', None) - self.add_file(path, **kwds) - - if not recursive: - break - - for r in results: - self.objects[r.id] = r - - return results - - def path_leaf(self, path): - head, tail = ntpath.split(path) - return tail or ntpath.basename(head) - - def add_file_if_doesnt_exist(self, f_path, parent=None, tree='SOURCE_ROOT', create_build_files=True, weak=False, ignore_unknown_type=False): - for obj in self.objects.values(): - if 'path' in obj: - if self.path_leaf(f_path) == self.path_leaf(obj.get('path')): - return [] - - return self.add_file(f_path, parent, tree, create_build_files, weak, ignore_unknown_type=ignore_unknown_type) - - def add_file(self, f_path, parent=None, tree='SOURCE_ROOT', create_build_files=True, weak=False, ignore_unknown_type=False): - results = [] - abs_path = '' - - if os.path.isabs(f_path): - abs_path = f_path - - if not os.path.exists(f_path): - return results - elif tree == 'SOURCE_ROOT': - f_path = os.path.relpath(f_path, self.source_root) - else: - tree = '' - - if not parent: - parent = self.root_group - elif not isinstance(parent, PBXGroup): - # assume it's an id - parent = self.objects.get(parent, self.root_group) - - file_ref = PBXFileReference.Create(f_path, tree, ignore_unknown_type=ignore_unknown_type) - parent.add_child(file_ref) - results.append(file_ref) - - # create a build file for the file ref - if file_ref.build_phase and create_build_files: - phases = self.get_build_phases(file_ref.build_phase) - - for phase in phases: - build_file = PBXBuildFile.Create(file_ref, weak=weak) - - phase.add_build_file(build_file) - results.append(build_file) - - if abs_path and tree == 'SOURCE_ROOT' \ - and os.path.isfile(abs_path) \ - and file_ref.build_phase == 'PBXFrameworksBuildPhase': - library_path = os.path.join('$(SRCROOT)', os.path.split(f_path)[0]) - self.add_library_search_paths([library_path], recursive=False) - - if abs_path and tree == 'SOURCE_ROOT' \ - and not os.path.isfile(abs_path) \ - and file_ref.build_phase == 'PBXFrameworksBuildPhase': - framework_path = os.path.join('$(SRCROOT)', os.path.split(f_path)[0]) - self.add_framework_search_paths([framework_path, '$(inherited)'], recursive=False) - - for r in results: - self.objects[r.id] = r - - if results: - self.modified = True - - return results - - def check_and_repair_framework(self, base): - name = os.path.basename(base) - - if ".framework" in name: - basename = name[:-len(".framework")] - - finalHeaders = os.path.join(base, "Headers") - finalCurrent = os.path.join(base, "Versions/Current") - finalLib = os.path.join(base, basename) - srcHeaders = "Versions/A/Headers" - srcCurrent = "A" - srcLib = "Versions/A/" + basename - - if not os.path.exists(finalHeaders): - os.symlink(srcHeaders, finalHeaders) - if not os.path.exists(finalCurrent): - os.symlink(srcCurrent, finalCurrent) - if not os.path.exists(finalLib): - os.symlink(srcLib, finalLib) - - - def remove_file(self, id, recursive=True): - if not PBXType.IsGuid(id): - id = id.id - - if id in self.objects: - self.objects.remove(id) - # Remove from PBXResourcesBuildPhase and PBXSourcesBuildPhase if necessary - buildFiles = [f for f in self.objects.values() if f.get('isa') == 'PBXBuildFile'] - for buildFile in buildFiles: - if id == buildFile.get('fileRef'): - key = buildFile.id - PBXRBP = [f for f in self.objects.values() if f.get('isa') == 'PBXResourcesBuildPhase'] - PBXSBP = [f for f in self.objects.values() if f.get('isa') == 'PBXSourcesBuildPhase'] - self.objects.remove(key) - if PBXSBP[0].has_build_file(key): - PBXSBP[0].remove_build_file(key) - if PBXRBP[0].has_build_file(key): - PBXRBP[0].remove_build_file(key) - if recursive: - groups = [g for g in self.objects.values() if g.get('isa') == 'PBXGroup'] - - for group in groups: - if id in group['children']: - group.remove_child(id) - - self.modified = True - - def remove_group(self, id, recursive = False): - if not PBXType.IsGuid(id): - id = id.id - name = self.objects.get(id).get('path') - children = self.objects.get(id).get('children') - if name is None: - name = id - if id in self.objects: - if recursive: - for childKey in children: - childValue = self.objects.get(childKey) - if childValue.get('isa') == 'PBXGroup': - self.remove_group(childKey, True) - else: - self.remove_file(childKey, False) - else: - return - else: - return - self.objects.remove(id); - - def remove_group_by_name(self, name, recursive = False): - groups = self.get_groups_by_name(name) - if len(groups): - for group in groups: - self.remove_group(group, recursive) - else: - return - - def move_file(self, id, dest_grp=None): - pass - - def apply_patch(self, patch_path, xcode_path): - if not os.path.isfile(patch_path) or not os.path.isdir(xcode_path): - print('ERROR: couldn\'t apply "%s" to "%s"' % (patch_path, xcode_path)) - return - - print('applying "%s" to "%s"' % (patch_path, xcode_path)) - - return subprocess.call(['patch', '-p1', '--forward', '--directory=%s' % xcode_path, '--input=%s' % patch_path]) - - def apply_mods(self, mod_dict, default_path=None): - if not default_path: - default_path = os.getcwd() - - keys = mod_dict.keys() - - for k in keys: - v = mod_dict.pop(k) - mod_dict[k.lower()] = v - - parent = mod_dict.pop('group', None) - - if parent: - parent = self.get_or_create_group(parent) - - excludes = mod_dict.pop('excludes', []) - - if excludes: - excludes = [re.compile(e) for e in excludes] - - compiler_flags = mod_dict.pop('compiler_flags', {}) - - for k, v in mod_dict.items(): - if k == 'patches': - for p in v: - if not os.path.isabs(p): - p = os.path.join(default_path, p) - - self.apply_patch(p, self.source_root) - elif k == 'folders': - # get and compile excludes list - # do each folder individually - for folder in v: - kwds = {} - - # if path contains ':' remove it and set recursive to False - if ':' in folder: - args = folder.split(':') - kwds['recursive'] = False - folder = args.pop(0) - - if os.path.isabs(folder) and os.path.isdir(folder): - pass - else: - folder = os.path.join(default_path, folder) - if not os.path.isdir(folder): - continue - - if parent: - kwds['parent'] = parent - - if excludes: - kwds['excludes'] = excludes - - self.add_folder(folder, **kwds) - elif k == 'headerpaths' or k == 'librarypaths': - paths = [] - - for p in v: - if p.endswith('/**'): - p = os.path.split(p)[0] - - if not os.path.isabs(p): - p = os.path.join(default_path, p) - - if not os.path.exists(p): - continue - - p = self.get_relative_path(p) - paths.append(os.path.join('$(SRCROOT)', p, "**")) - - if k == 'headerpaths': - self.add_header_search_paths(paths) - else: - self.add_library_search_paths(paths) - elif k == 'other_cflags': - self.add_other_cflags(v) - elif k == 'other_ldflags': - self.add_other_ldflags(v) - elif k == 'libs' or k == 'frameworks' or k == 'files': - paths = {} - - for p in v: - kwds = {} - - if ':' in p: - args = p.split(':') - p = args.pop(0) - - if 'weak' in args: - kwds['weak'] = True - - file_path = os.path.join(default_path, p) - search_path, file_name = os.path.split(file_path) - - if [m for m in excludes if re.match(m, file_name)]: - continue - - try: - expr = re.compile(file_name) - except re.error: - expr = None - - if expr and os.path.isdir(search_path): - file_list = os.listdir(search_path) - - for f in file_list: - if [m for m in excludes if re.match(m, f)]: - continue - - if re.search(expr, f): - kwds['name'] = f - paths[os.path.join(search_path, f)] = kwds - p = None - - if k == 'libs': - kwds['parent'] = self.get_or_create_group('Libraries', parent=parent) - elif k == 'frameworks': - kwds['parent'] = self.get_or_create_group('Frameworks', parent=parent) - - if p: - kwds['name'] = file_name - - if k == 'libs': - p = os.path.join('usr', 'lib', p) - kwds['tree'] = 'SDKROOT' - elif k == 'frameworks': - p = os.path.join('System', 'Library', 'Frameworks', p) - kwds['tree'] = 'SDKROOT' - elif k == 'files' and not os.path.exists(file_path): - # don't add non-existent files to the project. - continue - - paths[p] = kwds - - new_files = self.verify_files([n.get('name') for n in paths.values()]) - add_files = [(k, v) for k, v in paths.items() if v.get('name') in new_files] - - for path, kwds in add_files: - kwds.pop('name', None) - - if 'parent' not in kwds and parent: - kwds['parent'] = parent - - self.add_file(path, **kwds) - - if compiler_flags: - for k, v in compiler_flags.items(): - filerefs = [] - - for f in v: - filerefs.extend([fr.id for fr in self.objects.values() if fr.get('isa') == 'PBXFileReference' - and fr.get('name') == f]) - - buildfiles = [bf for bf in self.objects.values() if bf.get('isa') == 'PBXBuildFile' - and bf.get('fileRef') in filerefs] - - for bf in buildfiles: - if bf.add_compiler_flag(k): - self.modified = True - - def backup(self, file_name=None, backup_name=None): - if not file_name: - file_name = self.pbxproj_path - - if not backup_name: - backup_name = "%s.%s.backup" % (file_name, datetime.datetime.now().strftime('%d%m%y-%H%M%S')) - - shutil.copy2(file_name, backup_name) - return backup_name - - def save(self, file_name=None, old_format=False): - if old_format : - self.saveFormatXML(file_name) - else: - self.saveFormat3_2(file_name) - - def saveFormat3_2(self, file_name=None): - """Alias for backward compatibility""" - self.save_new_format(file_name) - - def save_format_xml(self, file_name=None): - """Saves in old (xml) format""" - if not file_name: - file_name = self.pbxproj_path - - # This code is adapted from plistlib.writePlist - with open(file_name, "w") as f: - writer = PBXWriter(f) - writer.writeln("") - writer.writeValue(self.data) - writer.writeln("") - - def save_new_format(self, file_name=None): - """Save in Xcode 3.2 compatible (new) format""" - if not file_name: - file_name = self.pbxproj_path - - # process to get the section's info and names - objs = self.data.get('objects') - sections = dict() - uuids = dict() - - for key in objs: - l = list() - - if objs.get(key).get('isa') in sections: - l = sections.get(objs.get(key).get('isa')) - - l.append(tuple([key, objs.get(key)])) - sections[objs.get(key).get('isa')] = l - - if 'name' in objs.get(key): - uuids[key] = objs.get(key).get('name') - elif 'path' in objs.get(key): - uuids[key] = objs.get(key).get('path') - else: - if objs.get(key).get('isa') == 'PBXProject': - uuids[objs.get(key).get('buildConfigurationList')] = 'Build configuration list for PBXProject "Unity-iPhone"' - elif objs.get(key).get('isa')[0:3] == 'PBX': - uuids[key] = objs.get(key).get('isa')[3:-10] - else: - uuids[key] = 'Build configuration list for PBXNativeTarget "TARGET_NAME"' - - ro = self.data.get('rootObject') - uuids[ro] = 'Project Object' - - for key in objs: - # transitive references (used in the BuildFile section) - if 'fileRef' in objs.get(key) and objs.get(key).get('fileRef') in uuids: - uuids[key] = uuids[objs.get(key).get('fileRef')] - - # transitive reference to the target name (used in the Native target section) - if objs.get(key).get('isa') == 'PBXNativeTarget': - uuids[objs.get(key).get('buildConfigurationList')] = uuids[objs.get(key).get('buildConfigurationList')].replace('TARGET_NAME', uuids[key]) - - self.uuids = uuids - self.sections = sections - - out = open(file_name, 'w') - out.write('// !$*UTF8*$!\n') - self._printNewXCodeFormat(out, self.data, '', enters=True) - out.close() - - @classmethod - def addslashes(cls, s): - d = {'"': '\\"', "'": "\\'", "\0": "\\\0", "\\": "\\\\", "\n":"\\n"} - return ''.join(d.get(c, c) for c in s) - - def _printNewXCodeFormat(self, out, root, deep, enters=True): - if isinstance(root, IterableUserDict): - out.write('{') - - if enters: - out.write('\n') - - isa = root.pop('isa', '') - - if isa != '': # keep the isa in the first spot - if enters: - out.write('\t' + deep) - - out.write('isa = ') - self._printNewXCodeFormat(out, isa, '\t' + deep, enters=enters) - out.write(';') - - if enters: - out.write('\n') - else: - out.write(' ') - - try: - iterkeys = root.iterkeys() - - except AttributeError: - # python 3 support - iterkeys = root.keys() - - for key in sorted(iterkeys): # keep the same order as Apple. - if enters: - out.write('\t' + deep) - - if re.match(regex, key).group(0) == key: - try: - out.write(key.encode("utf-8") + ' = ') - - except: - # python 3 support - out.write(key + ' = ') - else: - try: - out.write('"' + key.encode("utf-8") + '" = ') - - except: - # python 3 support - out.write('"' + key + '" = ') - - if key == 'objects': - out.write('{') # open the objects section - - if enters: - out.write('\n') - #root.remove('objects') # remove it to avoid problems - - sections = [ - ('PBXBuildFile', False), - ('PBXCopyFilesBuildPhase', True), - ('PBXFileReference', False), - ('PBXFrameworksBuildPhase', True), - ('PBXGroup', True), - ('PBXAggregateTarget', True), - ('PBXNativeTarget', True), - ('PBXProject', True), - ('PBXResourcesBuildPhase', True), - ('PBXShellScriptBuildPhase', True), - ('PBXSourcesBuildPhase', True), - ('XCBuildConfiguration', True), - ('XCConfigurationList', True), - ('PBXTargetDependency', True), - ('PBXVariantGroup', True), - ('PBXReferenceProxy', True), - ('PBXContainerItemProxy', True)] - - for section in sections: # iterate over the sections - if self.sections.get(section[0]) is None: - continue - - out.write('\n/* Begin %s section */' % section[0].encode("utf-8")) - - try: - self.sections.get(section[0]).sort(cmp=lambda x, y: cmp(x[0], y[0])) - - except: - # python 3 support - self.sections.get(section[0]).sort(key=lambda elem: elem[0]) - - for pair in self.sections.get(section[0]): - key = pair[0] - value = pair[1] - out.write('\n') - - if enters: - out.write('\t\t' + deep) - - try: - out.write(key.encode("utf-8")) - - except: - # python 3 support - out.write(key) - - if key in self.uuids: - try: - out.write(" /* " + self.uuids[key].encode("utf-8") + " */") - - except: - # python 3 support - out.write(" /* " + self.uuids[key] + " */") - - out.write(" = ") - self._printNewXCodeFormat(out, value, '\t\t' + deep, enters=section[1]) - out.write(';') - - try: - out.write('\n/* End %s section */\n' % section[0].encode("utf-8")) - - except: - # python 3 support - out.write('\n/* End %s section */\n' % section[0]) - - out.write(deep + '\t}') # close of the objects section - else: - self._printNewXCodeFormat(out, root[key], '\t' + deep, enters=enters) - - out.write(';') - - if enters: - out.write('\n') - else: - out.write(' ') - - root['isa'] = isa # restore the isa for further calls - - if enters: - out.write(deep) - - out.write('}') - - elif isinstance(root, UserList): - out.write('(') - - if enters: - out.write('\n') - - for value in root: - if enters: - out.write('\t' + deep) - - self._printNewXCodeFormat(out, value, '\t' + deep, enters=enters) - out.write(',') - - if enters: - out.write('\n') - - if enters: - out.write(deep) - - out.write(')') - - else: - if len(root) > 0 and re.match(regex, root).group(0) == root: - try: - out.write(root.encode("utf-8")) - - except: - # python 3 support - out.write(root) - - else: - try: - out.write('"' + XcodeProject.addslashes(root.encode("utf-8")) + '"') - - except: - # python 3 support - out.write('"' + XcodeProject.addslashes(root) + '"') - - if root in self.uuids: - try: - out.write(" /* " + self.uuids[root].encode("utf-8") + " */") - - except: - # python 3 support - out.write(" /* " + self.uuids[root] + " */") - - @classmethod - def Load(cls, path): - cls.plutil_path = os.path.join(os.path.split(__file__)[0], 'plutil') - - if not os.path.isfile(XcodeProject.plutil_path): - cls.plutil_path = 'plutil' - - # load project by converting to xml and then convert that using plistlib - p = subprocess.Popen([XcodeProject.plutil_path, '-convert', 'xml1', '-o', '-', path], stdout=subprocess.PIPE) - stdout, stderr = p.communicate() - - # If the plist was malformed, returncode will be non-zero - if p.returncode != 0: - print(stdout) - return None - - try: - tree = plistlib.readPlistFromString(stdout) - - except: - tree = plistlib.loads(stdout) - - return XcodeProject(tree, path) - - @classmethod - def LoadFromXML(cls, path): - tree = plistlib.readPlist(path) - return XcodeProject(tree, path) - - -# The code below was adapted from plistlib.py. - -class PBXWriter(PlistWriter): - def writeValue(self, value): - if isinstance(value, (PBXList, PBXDict)): - PlistWriter.writeValue(self, value.data) - else: - PlistWriter.writeValue(self, value) - - def simpleElement(self, element, value=None): - """ - We have to override this method to deal with Unicode text correctly. - Non-ascii characters have to get encoded as character references. - """ - if value is not None: - value = _escapeAndEncode(value) - self.writeln("<%s>%s" % (element, value, element)) - else: - self.writeln("<%s/>" % element) - - -# Regex to find any control chars, except for \t \n and \r -_controlCharPat = re.compile( - r"[\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0b\x0c\x0e\x0f" - r"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f]") - - -def _escapeAndEncode(text): - m = _controlCharPat.search(text) - if m is not None: - raise ValueError("strings can't contains control characters; " - "use plistlib.Data instead") - text = text.replace("\r\n", "\n") # convert DOS line endings - text = text.replace("\r", "\n") # convert Mac line endings - text = text.replace("&", "&") # escape '&' - text = text.replace("<", "<") # escape '<' - text = text.replace(">", ">") # escape '>' - return text.encode("ascii", "xmlcharrefreplace") # encode as ascii with xml character references - -def main(): - import json - import argparse - import subprocess - import shutil - import os - - parser = argparse.ArgumentParser("Modify an xcode project file using a single command at a time.") - parser.add_argument('project', help="Project path") - parser.add_argument('configuration', help="Modify the flags of the given configuration", choices=['Debug', 'Release', 'All']) - parser.add_argument('-af', help='Add a flag value, in the format key=value', action='append') - parser.add_argument('-rf', help='Remove a flag value, in the format key=value', action='append') - parser.add_argument('-b', '--backup', help='Create a temporary backup before modify', action='store_true') - args = parser.parse_args(); - - - # open the project file - if os.path.isdir(args.project) : - args.project = args.project + "/project.pbxproj" - - if not os.path.isfile(args.project) : - raise Exception("Project File not found") - - project = XcodeProject.Load(args.project) - backup_file = None - if args.backup : - backup_file = project.backup() - - # apply the commands - # add flags - if args.af : - pairs = {} - for flag in args.af: - tokens = flag.split("=") - pairs[tokens[0]] = tokens[1] - project.add_flags(pairs, args.configuration) - - # remove flags - if args.rf : - pairs = {} - for flag in args.rf: - tokens = flag.split("=") - pairs[tokens[0]] = tokens[1] - project.remove_flags(pairs, args.configuration) - - # save the file - project.save() - - # remove backup if everything was ok. - if args.backup : - os.remove(backup_file) - -if __name__ == "__main__": - main() diff --git a/tools/templates/{{ cookiecutter.project_name }}-ios/{{ cookiecutter.project_name }}.xcodeproj/project.pbxproj b/tools/templates/{{ cookiecutter.project_name }}-ios/{{ cookiecutter.project_name }}.xcodeproj/project.pbxproj index 0d00e86..cb58807 100755 --- a/tools/templates/{{ cookiecutter.project_name }}-ios/{{ cookiecutter.project_name }}.xcodeproj/project.pbxproj +++ b/tools/templates/{{ cookiecutter.project_name }}-ios/{{ cookiecutter.project_name }}.xcodeproj/project.pbxproj @@ -290,7 +290,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.1; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "{{ cookiecutter.dist_dir }}/lib" + "{{ cookiecutter.dist_dir }}/lib", ); ONLY_ACTIVE_ARCH = NO; OTHER_LDFLAGS = "-all_load"; @@ -325,7 +325,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.1; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "\"$(PROJECT_DIR)/../build/lib\"" + "\"$(PROJECT_DIR)/../build/lib\"", ); OTHER_LDFLAGS = "-all_load"; PRODUCT_NAME = {{ cookiecutter.project_name }}; @@ -344,6 +344,7 @@ buildSettings = { DEAD_CODE_STRIPPING = NO; USER_HEADER_SEARCH_PATHS = {{ cookiecutter.dist_dir }}/root/include/; + VALID_ARCHS = x86_64; }; name = Debug; }; @@ -353,6 +354,7 @@ DEAD_CODE_STRIPPING = NO; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; USER_HEADER_SEARCH_PATHS = {{ cookiecutter.dist_dir }}/root/include/; + VALID_ARCHS = x86_64; }; name = Release; }; From d6835dd826f612070f28d668838e63cb30e46aa4 Mon Sep 17 00:00:00 2001 From: Akshay Arora Date: Mon, 29 Oct 2018 15:13:10 +0530 Subject: [PATCH 19/42] Update __init__.py --- recipes/kivy/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipes/kivy/__init__.py b/recipes/kivy/__init__.py index 98c1c55..9b9b19d 100644 --- a/recipes/kivy/__init__.py +++ b/recipes/kivy/__init__.py @@ -3,7 +3,7 @@ from os.path import join class KivyRecipe(CythonRecipe): - version = "1.10.0" + version = "1.10.1" url = "https://github.com/kivy/kivy/archive/{version}.zip" library = "libkivy.a" depends = ["python", "sdl2", "sdl2_image", "sdl2_mixer", "sdl2_ttf", "ios", From 9bd149335cc7c852de16ea8fe12e404e68e47d77 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Tue, 30 Oct 2018 14:56:56 +0100 Subject: [PATCH 20/42] fix missing pbx framework for latest sdl2 --- recipes/sdl2/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipes/sdl2/__init__.py b/recipes/sdl2/__init__.py index 6fe77cf..a13b41c 100644 --- a/recipes/sdl2/__init__.py +++ b/recipes/sdl2/__init__.py @@ -10,7 +10,7 @@ class LibSDL2Recipe(Recipe): library = "Xcode-iOS/SDL/build/Release-{arch.sdk}/libSDL2.a" include_dir = "include" pbx_frameworks = ["OpenGLES", "AudioToolbox", "QuartzCore", "CoreGraphics", - "CoreMotion"] + "CoreMotion", "GameController", "AVFoundation", "Metal"] def prebuild_arch(self, arch): if self.has_marker("patched"): From 5a8b47ec19466dcec2c2b12f570ac57151a08c9d Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Tue, 30 Oct 2018 14:59:29 +0100 Subject: [PATCH 21/42] update to SDL2 2.0.8, dont use the special branch anymore. Tested on iPAD with iOS 9 --- recipes/sdl2/__init__.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/recipes/sdl2/__init__.py b/recipes/sdl2/__init__.py index a13b41c..22acf40 100644 --- a/recipes/sdl2/__init__.py +++ b/recipes/sdl2/__init__.py @@ -3,10 +3,10 @@ import sh class LibSDL2Recipe(Recipe): - #version = "2.0.3" - #url = "https://www.libsdl.org/release/SDL2-{version}.tar.gz" - version = "iOS-improvements" - url = "https://bitbucket.org/slime73/sdl-experiments/get/{version}.tar.gz" + version = "2.0.8" + url = "https://www.libsdl.org/release/SDL2-{version}.tar.gz" + #version = "iOS-improvements" + #url = "https://bitbucket.org/slime73/sdl-experiments/get/{version}.tar.gz" library = "Xcode-iOS/SDL/build/Release-{arch.sdk}/libSDL2.a" include_dir = "include" pbx_frameworks = ["OpenGLES", "AudioToolbox", "QuartzCore", "CoreGraphics", @@ -20,15 +20,16 @@ class LibSDL2Recipe(Recipe): def build_arch(self, arch): env = arch.get_env() + quiet = ["-quiet"] if self.ctx.quiet else [] shprint(sh.xcodebuild, self.ctx.concurrent_xcodebuild, "ONLY_ACTIVE_ARCH=NO", "ARCHS={}".format(arch.arch), "CC={}".format(env['CC']), "-sdk", arch.sdk, "-project", "Xcode-iOS/SDL/SDL.xcodeproj", - "-target", "libSDL", - "-configuration", "Release") + "-target", "libSDL-iOS", + "-configuration", "Release", + *quiet) recipe = LibSDL2Recipe() - From a732b7526a9f8627c45eb6398ee94755f38b20a1 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Tue, 30 Oct 2018 17:05:59 +0100 Subject: [PATCH 22/42] remove about quiet --- recipes/sdl2/__init__.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/recipes/sdl2/__init__.py b/recipes/sdl2/__init__.py index 22acf40..df2f8a1 100644 --- a/recipes/sdl2/__init__.py +++ b/recipes/sdl2/__init__.py @@ -20,7 +20,6 @@ class LibSDL2Recipe(Recipe): def build_arch(self, arch): env = arch.get_env() - quiet = ["-quiet"] if self.ctx.quiet else [] shprint(sh.xcodebuild, self.ctx.concurrent_xcodebuild, "ONLY_ACTIVE_ARCH=NO", "ARCHS={}".format(arch.arch), @@ -28,8 +27,7 @@ class LibSDL2Recipe(Recipe): "-sdk", arch.sdk, "-project", "Xcode-iOS/SDL/SDL.xcodeproj", "-target", "libSDL-iOS", - "-configuration", "Release", - *quiet) + "-configuration", "Release") recipe = LibSDL2Recipe() From 7baf869fac3f671846c15b493047d8faa4cbff94 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Wed, 31 Oct 2018 11:34:51 +0100 Subject: [PATCH 23/42] add hostpython3 recipe --- recipes/hostpython3/__init__.py | 119 ++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 recipes/hostpython3/__init__.py diff --git a/recipes/hostpython3/__init__.py b/recipes/hostpython3/__init__.py new file mode 100644 index 0000000..3fa646c --- /dev/null +++ b/recipes/hostpython3/__init__.py @@ -0,0 +1,119 @@ +from toolchain import Recipe, shprint, ensure_dir +from os.path import join, exists +import os +import sh +import shutil + + +class Hostpython3Recipe(Recipe): + version = "3.7.1" + url = "https://www.python.org/ftp/python/{version}/Python-{version}.tgz" + depends = [] + optional_depends = ["openssl"] + archs = ["x86_64"] + + def init_with_ctx(self, ctx): + super(Hostpython3Recipe, self).init_with_ctx(ctx) + self.ctx.hostpython = join(self.ctx.dist_dir, "hostpython3", "bin", "python") + self.ctx.hostpgen = join(self.ctx.dist_dir, "hostpython3", "bin", "pgen") + print("Global: hostpython located at {}".format(self.ctx.hostpython)) + print("Global: hostpgen located at {}".format(self.ctx.hostpgen)) + + def prebuild_arch(self, arch): + if self.has_marker("patched"): + return + # self.copy_file("_scproxy.py", "Lib/_scproxy.py") + # self.apply_patch("ssize-t-max.patch") + # self.apply_patch("dynload.patch") + # self.apply_patch("static-_sqlite3.patch") + shutil.copy("Modules/Setup.dist", "Modules/Setup") + # if "openssl.build_all" in self.ctx.state: + # self.append_file("ModulesSetup.openssl", "Modules/Setup.local") + self.set_marker("patched") + + def postbuild_arch(self, arch): + return + """ + makefile_fn = join(self.build_dir, "Makefile") + with open(makefile_fn) as fd: + lines = fd.readlines() + for index, line in enumerate(lines): + if "-bundle" not in line: + continue + parts = line.split(" ") + parts.remove("-bundle") + if "-bundle_loader" in parts: + i = parts.index("-bundle_loader") + parts.pop(i) + parts.pop(i) + lines[index] = " ".join(parts) + with open(makefile_fn, "w") as fd: + fd.writelines(lines) + """ + + def get_build_env(self): + sdk_path = sh.xcrun("--sdk", "macosx", "--show-sdk-path").strip() + build_env = self.ctx.env.copy() + self.build_env_x86_84 = build_env + ccache = (build_env["CCACHE"] + ' ') if 'CCACHE' in build_env else '' + build_env["CC"] = ccache + "clang -Qunused-arguments -fcolor-diagnostics" + build_env["LDFLAGS"] = " ".join([ + "-lsqlite3", + "-lffi", + "-L{}".format(join(self.ctx.dist_dir, "hostlibffi", "usr", "local", "lib")) + ]) + build_env["CFLAGS"] = " ".join([ + "--sysroot={}".format(sdk_path), + "-arch x86_64", + "-mmacosx-version-min=10.12", + "-I{}".format(join(self.ctx.dist_dir, "hostlibffi", "usr", "local", "include")) + ]) + if "openssl.build_all" in self.ctx.state: + build_env["LDFLAGS"] += " -L{}".format(join(self.ctx.dist_dir, "lib")) + build_env["CFLAGS"] += " -I{}".format(join(self.ctx.dist_dir, "include", + "x86_64", "openssl")) + return build_env + + def build_x86_64(self): + build_env = self.get_build_env() + configure = sh.Command(join(self.build_dir, "configure")) + shprint(configure, + "--prefix={}".format(join(self.ctx.dist_dir, "hostpython3")), + # "--disable-toolbox-glue", + # "--without-gcc", + _env=build_env) + shprint(sh.make, "-C", self.build_dir, self.ctx.concurrent_make, + _env=build_env) + # shutil.move("python", "hostpython") + # shutil.move("Parser/pgen", "Parser/hostpgen") + + def install(self): + arch = list(self.filtered_archs)[0] + build_env = self.get_build_env() + build_dir = self.get_build_dir(arch.arch) + build_env["PATH"] = os.environ["PATH"] + # Compiling sometimes looks for Python-ast.py in the 'Python' i.s.o. + # the 'hostpython' folder. Create a symlink to fix. See issue #201 + # shprint(sh.ln, "-s", + # join(build_dir, "hostpython3"), + # join(build_dir, "Python")) + shprint(sh.make, self.ctx.concurrent_make, + "-C", build_dir, + "bininstall", "inclinstall", + _env=build_env) + pylib_dir = join(self.ctx.dist_dir, "hostpython3", "lib", "python3.7") + if exists(pylib_dir): + shutil.rmtree(pylib_dir) + shutil.copytree( + join(build_dir, "Lib"), + pylib_dir) + ensure_dir(join(pylib_dir, "config")) + shutil.copy( + join(build_dir, "Makefile"), + join(pylib_dir, "config", "Makefile")) + # shutil.copy( + # join(build_dir, "Parser", "pgen"), + # join(self.ctx.dist_dir, "hostpython3", "bin", "pgen")) + + +recipe = Hostpython3Recipe() From 307cbd134a07014b49763e7bc7615635a4f10448 Mon Sep 17 00:00:00 2001 From: Brent Picasso Date: Wed, 31 Oct 2018 17:51:56 -0700 Subject: [PATCH 24/42] update requirements --- README.rst | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 99d34e1..f0f32cb 100644 --- a/README.rst +++ b/README.rst @@ -22,9 +22,13 @@ Requirements Currently, the toolchain requires a few tools for compilation. You will need: -#. Ensure you have the right dependencies installed:: +#. Ensure you have python3 installed - this is needed for toolchain.py:: - pip install -r requirements.txt + brew install python + +#. Ensure you have the right dependencies installed for python3:: + + pip3 install -r requirements.txt #. Xcode 10 or above, with an iOS SDK and command line tools installed:: @@ -35,10 +39,10 @@ Currently, the toolchain requires a few tools for compilation. You will need: brew install autoconf automake libtool pkg-config brew link libtool -#. Install Cython (0.25.2):: +#. Install Cython (0.26.1):: # pip method if available (sudo might be needed.) - pip install cython==0.25.2 + pip install cython==0.26.1 Using the toolchain From 3c77617141542fe6bb6aac897aff554cd3c1ec08 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Thu, 1 Nov 2018 20:39:28 +0100 Subject: [PATCH 25/42] sdl2: fix missing pbx frameworks --- recipes/sdl2/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/recipes/sdl2/__init__.py b/recipes/sdl2/__init__.py index df2f8a1..eb4b8fb 100644 --- a/recipes/sdl2/__init__.py +++ b/recipes/sdl2/__init__.py @@ -9,8 +9,10 @@ class LibSDL2Recipe(Recipe): #url = "https://bitbucket.org/slime73/sdl-experiments/get/{version}.tar.gz" library = "Xcode-iOS/SDL/build/Release-{arch.sdk}/libSDL2.a" include_dir = "include" - pbx_frameworks = ["OpenGLES", "AudioToolbox", "QuartzCore", "CoreGraphics", - "CoreMotion", "GameController", "AVFoundation", "Metal"] + pbx_frameworks = [ + "OpenGLES", "AudioToolbox", "QuartzCore", "CoreGraphics", + "CoreMotion", "GameController", "AVFoundation", "Metal", + "UIKit"] def prebuild_arch(self, arch): if self.has_marker("patched"): From 7ed286efa86e61d79ab49a1a8b496ad03f8d286f Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Thu, 1 Nov 2018 20:40:01 +0100 Subject: [PATCH 26/42] hostpython3: enforce zlib compilation --- recipes/hostpython3/ModulesSetup | 1 + recipes/hostpython3/__init__.py | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 15 deletions(-) create mode 100644 recipes/hostpython3/ModulesSetup diff --git a/recipes/hostpython3/ModulesSetup b/recipes/hostpython3/ModulesSetup new file mode 100644 index 0000000..1d86370 --- /dev/null +++ b/recipes/hostpython3/ModulesSetup @@ -0,0 +1 @@ +zlib zlibmodule.c -I$(prefix)/include -lz diff --git a/recipes/hostpython3/__init__.py b/recipes/hostpython3/__init__.py index 3fa646c..7d99b86 100644 --- a/recipes/hostpython3/__init__.py +++ b/recipes/hostpython3/__init__.py @@ -22,11 +22,11 @@ class Hostpython3Recipe(Recipe): def prebuild_arch(self, arch): if self.has_marker("patched"): return - # self.copy_file("_scproxy.py", "Lib/_scproxy.py") + self.copy_file("ModulesSetup", "Modules/Setup.local") # self.apply_patch("ssize-t-max.patch") # self.apply_patch("dynload.patch") # self.apply_patch("static-_sqlite3.patch") - shutil.copy("Modules/Setup.dist", "Modules/Setup") + # shutil.copy("Modules/Setup.dist", "Modules/Setup") # if "openssl.build_all" in self.ctx.state: # self.append_file("ModulesSetup.openssl", "Modules/Setup.local") self.set_marker("patched") @@ -99,21 +99,21 @@ class Hostpython3Recipe(Recipe): # join(build_dir, "Python")) shprint(sh.make, self.ctx.concurrent_make, "-C", build_dir, - "bininstall", "inclinstall", + "install", _env=build_env) - pylib_dir = join(self.ctx.dist_dir, "hostpython3", "lib", "python3.7") - if exists(pylib_dir): - shutil.rmtree(pylib_dir) - shutil.copytree( - join(build_dir, "Lib"), - pylib_dir) - ensure_dir(join(pylib_dir, "config")) - shutil.copy( - join(build_dir, "Makefile"), - join(pylib_dir, "config", "Makefile")) + # pylib_dir = join(self.ctx.dist_dir, "hostpython3", "lib", "python3.7") + # if exists(pylib_dir): + # shutil.rmtree(pylib_dir) + # shutil.copytree( + # join(build_dir, "Lib"), + # pylib_dir) + # ensure_dir(join(pylib_dir, "config")) # shutil.copy( - # join(build_dir, "Parser", "pgen"), - # join(self.ctx.dist_dir, "hostpython3", "bin", "pgen")) + # join(build_dir, "Makefile"), + # join(pylib_dir, "config", "Makefile")) + shutil.copy( + join(self.ctx.dist_dir, "hostpython3", "bin", "python3"), + join(self.ctx.dist_dir, "hostpython3", "bin", "python")) recipe = Hostpython3Recipe() From 6c043cf9f3cd5f79a95d958ea90cef86ed8ec406 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Thu, 1 Nov 2018 21:53:18 +0100 Subject: [PATCH 27/42] python3: recipe with cross compilation patch + example of main.m that works --- recipes/python3/__init__.py | 150 +++++++++++++++++++++++++++ recipes/python3/xcompile.patch | 145 ++++++++++++++++++++++++++ tests/test_python3/main.m | 184 +++++++++++++++++++++++++++++++++ tests/test_python3/main.py | 1 + 4 files changed, 480 insertions(+) create mode 100644 recipes/python3/__init__.py create mode 100644 recipes/python3/xcompile.patch create mode 100644 tests/test_python3/main.m create mode 100644 tests/test_python3/main.py diff --git a/recipes/python3/__init__.py b/recipes/python3/__init__.py new file mode 100644 index 0000000..41ae1d1 --- /dev/null +++ b/recipes/python3/__init__.py @@ -0,0 +1,150 @@ +from toolchain import Recipe, shprint +from os.path import join +import sh +import shutil +import os + + +class Python3Recipe(Recipe): + version = "3.7.1" + url = "https://www.python.org/ftp/python/{version}/Python-{version}.tgz" + depends = ["hostpython3", "libffi", ] + optional_depends = ["openssl"] + library = "libpython3.7m.a" + pbx_libraries = ["libz", "libbz2", "libsqlite3"] + + def init_with_ctx(self, ctx): + super(Python3Recipe, self).init_with_ctx(ctx) + self.ctx.python_ver_dir = "python3.7" + self.ctx.python_prefix = join(ctx.dist_dir, "root", "python") + self.ctx.site_packages_dir = join( + ctx.dist_dir, "root", "python", "lib", ctx.python_ver_dir, + "site-packages") + + def prebuild_arch(self, arch): + # common to all archs + if self.has_marker("patched"): + return + # self.apply_patch("ssize-t-max.patch") + # self.apply_patch("dynload.patch") + # self.apply_patch("static-_sqlite3.patch") + shutil.copy("Modules/Setup.dist", "Modules/Setup") + self.apply_patch("xcompile.patch") + # self.copy_file("_scproxy.py", "Lib/_scproxy.py") + # self.apply_patch("xcompile.patch") + # self.apply_patch("setuppath.patch") + # self.append_file("ModulesSetup.mobile", "Modules/Setup.local") + # self.apply_patch("ipv6.patch") + # if "openssl.build_all" in self.ctx.state: + # self.append_file("ModulesSetup.openssl", "Modules/Setup.local") + # self.apply_patch("posixmodule.patch") + self.set_marker("patched") + + def get_build_env(self, arch): + build_env = arch.get_env() + build_env["PATH"] = "{}:{}".format( + join(self.ctx.dist_dir, "hostpython3", "bin"), + os.environ["PATH"]) + return build_env + + def build_arch(self, arch): + build_env = self.get_build_env(arch) + configure = sh.Command(join(self.build_dir, "configure")) + py_arch = arch.arch + if py_arch == "armv7": + py_arch = "arm" + elif py_arch == "arm64": + py_arch = "aarch64" + prefix = join(self.ctx.dist_dir, "python3") + shprint(configure, + "CC={}".format(build_env["CC"]), + "LD={}".format(build_env["LD"]), + "CFLAGS={}".format(build_env["CFLAGS"]), + "LDFLAGS={} -undefined dynamic_lookup".format(build_env["LDFLAGS"]), + # "--without-pymalloc", + # "--disable-toolbox-glue", + "ac_cv_file__dev_ptmx=yes", + "ac_cv_file__dev_ptc=no", + "ac_cv_little_endian_double=yes", + "ac_cv_func_memrchr=no", + "ac_cv_func_getentropy=no", + "ac_cv_func_getresuid=no", + "ac_cv_func_getresgid=no", + "ac_cv_func_setresgid=no", + "ac_cv_func_setresuid=no", + "ac_cv_func_plock=no", + "ac_cv_func_dup3=no", + "ac_cv_func_pipe2=no", + "ac_cv_func_preadv=no", + "ac_cv_func_pwritev=no", + "ac_cv_func_preadv2=no", + "ac_cv_func_pwritev2=no", + "ac_cv_func_mkfifoat=no", + "ac_cv_func_mknodat=no", + "ac_cv_func_posix_fadvise=no", + "ac_cv_func_posix_fallocate=no", + "ac_cv_func_sigwaitinfo=no", + "ac_cv_func_sigtimedwait=no", + "ac_cv_func_clock_settime=no", + "ac_cv_func_pthread_getcpuclockid=no", + "ac_cv_func_sched_setscheduler=no", + "ac_cv_func_sched_setparam=no", + "ac_cv_func_clock_gettime=no", + "--host={}-apple-ios".format(py_arch), + "--build=x86_64-apple-darwin", + "--prefix={}".format(prefix), + "--exec-prefix={}".format(prefix), + "--without-ensurepip", + # "--with-system-ffi", + # "--without-doc-strings", + "--enable-ipv6", + _env=build_env) + + # self._patch_pyconfig() + # self.apply_patch("ctypes_duplicate.patch") + # self.apply_patch("ctypes_duplicate_longdouble.patch") + shprint(sh.make, self.ctx.concurrent_make) + # "HOSTPYTHON={}".format(self.ctx.hostpython), + # "HOSTPGEN={}".format(self.ctx.hostpgen)) + # "CROSS_COMPILE_TARGET=yes", + + def install(self): + arch = list(self.filtered_archs)[0] + build_env = self.get_build_env(arch) + build_dir = self.get_build_dir(arch.arch) + shprint(sh.make, self.ctx.concurrent_make, + "-C", build_dir, + "install", + "prefix={}".format(join(self.ctx.dist_dir, "root", "python3")), + _env=build_env) + self.reduce_python() + + def reduce_python(self): + print("Reduce python") + oldpwd = os.getcwd() + try: + print("Remove files unlikely to be used") + os.chdir(join(self.ctx.dist_dir, "root", "python3")) + sh.rm("-rf", "share") + os.chdir(join( + self.ctx.dist_dir, "root", "python3", "lib", + "python3.7", "config-3.7m-darwin")) + sh.rm("libpython3.7m.a") + sh.rm("python.o") + sh.rm("config.c.in") + sh.rm("makesetup") + sh.rm("install-sh") + os.chdir(join(self.ctx.dist_dir, "root", "python3", "lib", "python3.7")) + # sh.find(".", "-iname", "*.pyc", "-exec", "rm", "{}", ";") + # sh.find(".", "-iname", "*.py", "-exec", "rm", "{}", ";") + #sh.find(".", "-iname", "test*", "-exec", "rm", "-rf", "{}", ";") + sh.rm("-rf", "wsgiref", "curses", "idlelib", "lib2to3") + + # now create the zip. + print("Create a stdlib.zip") + sh.zip("-r", "../stdlib.zip", sh.glob("*")) + finally: + os.chdir(oldpwd) + + +recipe = Python3Recipe() diff --git a/recipes/python3/xcompile.patch b/recipes/python3/xcompile.patch new file mode 100644 index 0000000..f3c2ec9 --- /dev/null +++ b/recipes/python3/xcompile.patch @@ -0,0 +1,145 @@ +--- Python-3.7.1.orig/config.sub 2018-10-20 08:04:19.000000000 +0200 ++++ Python-3.7.1/config.sub 2018-10-31 13:31:22.000000000 +0100 +@@ -249,7 +249,7 @@ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arceb \ +- | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv6m | armv[78][arm] \ ++ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv6m | armv[78][armk] \ + | avr | avr32 \ + | ba \ + | be32 | be64 \ +@@ -1524,7 +1524,11 @@ + ;; + -nacl*) + ;; +- -ios) ++ -ios*) ++ ;; ++ -tvos*) ++ ;; ++ -watchos*) + ;; + -none) + ;; +--- Python-3.7.1.orig/configure 2018-10-20 08:04:19.000000000 +0200 ++++ Python-3.7.1/configure 2018-10-31 13:41:38.000000000 +0100 +@@ -3253,6 +3253,15 @@ + *-*-cygwin*) + ac_sys_system=Cygwin + ;; ++ *-apple-ios) ++ ac_sys_system=iOS ++ ;; ++ *-apple-tvos) ++ ac_sys_system=tvOS ++ ;; ++ *-apple-watchos) ++ ac_sys_system=watchOS ++ ;; + *) + # for now, limit cross builds to known configurations + MACHDEP="unknown" +@@ -3294,6 +3303,15 @@ + _host_cpu=$host_cpu + esac + ;; ++ *-apple-*) ++ case "$host_cpu" in ++ arm*) ++ _host_cpu=arm ++ ;; ++ *) ++ _host_cpu=$host_cpu ++ esac ++ ;; + *-*-cygwin*) + _host_cpu= + ;; +@@ -3369,6 +3387,13 @@ + define_xopen_source=no;; + Darwin/1[0-9].*) + define_xopen_source=no;; ++ # On iOS, defining _POSIX_C_SOURCE also disables platform specific features. ++ iOS/*) ++ define_xopen_source=no;; ++ tvOS/*) ++ define_xopen_source=no;; ++ watchOS/*) ++ define_xopen_source=no;; + # On AIX 4 and 5.1, mbstate_t is defined only when _XOPEN_SOURCE == 500 but + # used in wcsnrtombs() and mbsnrtowcs() even if _XOPEN_SOURCE is not defined + # or has another value. By not (re)defining it, the defaults come in place. +@@ -6176,11 +6201,17 @@ + fi + + if test "$cross_compiling" = yes; then +- case "$READELF" in +- readelf|:) +- as_fn_error $? "readelf for the host is required for cross builds" "$LINENO" 5 +- ;; +- esac ++ case "$host" in ++ *-apple-*os) ++ # readelf not required for iOS cross builds. ++ ;; ++ *) ++ case "$READELF" in ++ readelf|:) ++ as_fn_error $? "readelf for the host is required for cross builds" "$LINENO" 5 ++ ;; ++ esac ++ esac + fi + + +@@ -6803,8 +6834,6 @@ + # tweak BASECFLAGS based on compiler and platform + case $GCC in + yes) +- CFLAGS_NODIST="$CFLAGS_NODIST -std=c99" +- + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -Wextra" >&5 + $as_echo_n "checking for -Wextra... " >&6; } + ac_save_cc="$CC" +@@ -11281,6 +11310,10 @@ + fi + ;; + hp*|HP*) DYNLOADFILE="dynload_hpux.o";; ++ # Disable dynamic loading on iOS ++ iOS/*) DYNLOADFILE="dynload_stub.o";; ++ tvOS/*) DYNLOADFILE="dynload_stub.o";; ++ watchOS/*) DYNLOADFILE="dynload_stub.o";; + *) + # use dynload_shlib.c and dlopen() if we have it; otherwise stub + # out any dynamic loading +@@ -18383,4 +18416,3 @@ + echo "" >&6 + echo "" >&6 + fi +- +--- Python-3.7.1.orig/Modules/posixmodule.c 2018-10-20 08:04:19.000000000 +0200 ++++ Python-3.7.1/Modules/posixmodule.c 2018-10-31 15:00:14.000000000 +0100 +@@ -194,6 +194,22 @@ + #endif /* _MSC_VER */ + #endif /* ! __WATCOMC__ || __QNX__ */ + ++// iOS ++#undef HAVE_EXECV ++#undef HAVE_FORK ++#undef HAVE_FORK1 ++#undef HAVE_FORKPTY ++#undef HAVE_GETGROUPS ++#undef HAVE_SCHED_H ++#undef HAVE_SENDFILE ++#undef HAVE_SETPRIORITY ++#undef HAVE_SPAWNV ++#undef HAVE_WAIT ++#undef HAVE_WAIT3 ++#undef HAVE_WAIT4 ++#undef HAVE_WAITPID ++#undef HAVE_SYSTEM ++#undef HAVE_FEXECVE + + /*[clinic input] + # one of the few times we lie about this name! diff --git a/tests/test_python3/main.m b/tests/test_python3/main.m new file mode 100644 index 0000000..873bd8b --- /dev/null +++ b/tests/test_python3/main.m @@ -0,0 +1,184 @@ +// +// main.m +// test_python3 +// + +#import +#import +#include "/Users/tito/code/kivy-ios/dist/root/python3/include/python3.7m/Python.h" +#include "/Users/tito/code/kivy-ios/dist/include/common/sdl2/SDL_main.h" +#include + +void export_orientation(); +void load_custom_builtin_importer(); + +int main(int argc, char *argv[]) { + int ret = 0; + + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + + // Change the executing path to YourApp + chdir("YourApp"); + + // Special environment to prefer .pyo, and don't write bytecode if .py are found + // because the process will not have a write attribute on the device. +// putenv("PYTHONOPTIMIZE=2"); + putenv("PYTHONDONTWRITEBYTECODE=1"); + putenv("PYTHONNOUSERSITE=1"); +// putenv("PYTHONPATH=."); +// putenv("PYTHONVERBOSE=1"); + putenv("PYTHONUNBUFFERED=1"); + + // Kivy environment to prefer some implementation on iOS platform + putenv("KIVY_BUILD=ios"); + putenv("KIVY_NO_CONFIG=1"); + putenv("KIVY_NO_FILELOG=1"); + putenv("KIVY_WINDOW=sdl2"); + putenv("KIVY_IMAGE=imageio,tex"); + putenv("KIVY_AUDIO=sdl2"); + putenv("KIVY_GL_BACKEND=sdl2"); + #ifndef DEBUG + putenv("KIVY_NO_CONSOLELOG=1"); + #endif + + // Export orientation preferences for Kivy + export_orientation(); + + NSString * resourcePath = [[NSBundle mainBundle] resourcePath]; +#if PY_MAJOR_VERSION == 2 + NSLog(@"PythonHome is: %s", (char *)[resourcePath UTF8String]); + Py_SetPythonHome((char *)[resourcePath UTF8String]); +#else + NSString *python_home = [NSString stringWithFormat:@"PYTHONHOME=%@", resourcePath, nil]; + putenv((char *)[python_home UTF8String]); + + NSString *python_path = [NSString stringWithFormat:@"PYTHONPATH=%@:%@/lib/python3.7/:%@/lib/python3.7/site-packages", resourcePath, resourcePath, resourcePath, nil]; + putenv((char *)[python_path UTF8String]); + + NSString *tmp_path = [NSString stringWithFormat:@"TMP=%@/tmp", resourcePath, nil]; + putenv((char *)[tmp_path UTF8String]); +#endif + + NSLog(@"Initializing python"); + Py_Initialize(); + +#if PY_MAJOR_VERSION == 2 + PySys_SetArgv(argc, argv); +#else + wchar_t** python_argv = PyMem_RawMalloc(sizeof(wchar_t *) *argc); + for (int i = 0; i < argc; i++) + python_argv[i] = Py_DecodeLocale(argv[i], NULL); + PySys_SetArgv(argc, python_argv); +#endif + + // If other modules are using the thread, we need to initialize them before. + PyEval_InitThreads(); + + // Add an importer for builtin modules + load_custom_builtin_importer(); + + // Search and start main.py +#if PY_MAJOR_VERSION == 2 +#define MAIN_EXT @"pyo" +#else +#define MAIN_EXT @"py" +#endif + + const char * prog = [ + [[NSBundle mainBundle] pathForResource:@"YourApp/main" ofType:MAIN_EXT] cStringUsingEncoding: + NSUTF8StringEncoding]; + NSLog(@"Running main.py: %s", prog); + FILE* fd = fopen(prog, "r"); + if ( fd == NULL ) { + ret = 1; + NSLog(@"Unable to open main.py, abort."); + } else { + ret = PyRun_SimpleFileEx(fd, prog, 1); + if (ret != 0) + NSLog(@"Application quit abnormally!"); + } + + Py_Finalize(); + NSLog(@"Leaving"); + + [pool release]; + + // Look like the app still runs even when we left here. + exit(ret); + return ret; +} + +// This method reads the available orientations from the Info.plist file and +// shares them via an environment variable. Kivy will automatically set the +// orientation according to this environment value, if it exists. To restrict +// the allowed orientation, please see the comments inside. +void export_orientation() { + NSDictionary *info = [[NSBundle mainBundle] infoDictionary]; + NSArray *orientations = [info objectForKey:@"UISupportedInterfaceOrientations"]; + + // Orientation restrictions + // ======================== + // Comment or uncomment blocks 1-3 in order the limit orientation support + + // 1. Landscape only + // NSString *result = [[NSString alloc] initWithString:@"KIVY_ORIENTATION=LandscapeLeft LandscapeRight"]; + + // 2. Portrait only + // NSString *result = [[NSString alloc] initWithString:@"KIVY_ORIENTATION=Portrait PortraitUpsideDown"]; + + // 3. All orientations + NSString *result = [[NSString alloc] initWithString:@"KIVY_ORIENTATION="]; + for (int i = 0; i < [orientations count]; i++) { + NSString *item = [orientations objectAtIndex:i]; + item = [item substringFromIndex:22]; + if (i > 0) + result = [result stringByAppendingString:@" "]; + result = [result stringByAppendingString:item]; + } + // ======================== + + putenv((char *)[result UTF8String]); + NSLog(@"Available orientation: %@", result); +} + +void load_custom_builtin_importer() { + static const char *custom_builtin_importer = \ + "import sys, imp\n" \ + "from os import environ\n" \ + "from os.path import exists, join\n" \ + "# Fake redirection to supress console output\n" \ + "if environ.get('KIVY_NO_CONSOLE', '0') == '1':\n" \ + " class fakestd(object):\n" \ + " def write(self, *args, **kw): pass\n" \ + " def flush(self, *args, **kw): pass\n" \ + " sys.stdout = fakestd()\n" \ + " sys.stderr = fakestd()\n" \ + "# Custom builtin importer for precompiled modules\n" \ + "class CustomBuiltinImporter(object):\n" \ + " def find_module(self, fullname, mpath=None):\n" \ + " if '.' not in fullname:\n" \ + " return\n" \ + " if not mpath:\n" \ + " return\n" \ + " part = fullname.rsplit('.')[-1]\n" \ + " fn = join(mpath[0], '{}.so'.format(part))\n" \ + " if exists(fn):\n" \ + " return self\n" \ + " return\n" \ + " def load_module(self, fullname):\n" \ + " f = fullname.replace('.', '_')\n" \ + " mod = sys.modules.get(f)\n" \ + " if mod is None:\n" \ + " # print 'LOAD DYNAMIC', f, sys.modules.keys()\n" \ + " try:\n" \ + " mod = imp.load_dynamic(f, f)\n" \ + " except ImportError:\n" \ + " # import traceback; traceback.print_exc();\n" \ + " # print 'LOAD DYNAMIC FALLBACK', fullname\n" \ + " mod = imp.load_dynamic(fullname, fullname)\n" \ + " sys.modules[fullname] = mod\n" \ + " return mod\n" \ + " return mod\n" \ + "sys.meta_path.append(CustomBuiltinImporter())"; + PyRun_SimpleString(custom_builtin_importer); +} diff --git a/tests/test_python3/main.py b/tests/test_python3/main.py new file mode 100644 index 0000000..98440b8 --- /dev/null +++ b/tests/test_python3/main.py @@ -0,0 +1 @@ +print("Python 3 running!") From 9762ee754c98d3f16da2daa1b799a1ad5ea703c1 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Fri, 2 Nov 2018 11:42:54 +0100 Subject: [PATCH 28/42] move hostpython/python to hostpython2/python2 --- recipes/{hostpython => hostpython2}/ModulesSetup | 0 recipes/{hostpython => hostpython2}/ModulesSetup.openssl | 0 recipes/{hostpython => hostpython2}/__init__.py | 0 recipes/{hostpython => hostpython2}/_scproxy.py | 0 recipes/{hostpython => hostpython2}/dynload.patch | 0 recipes/{hostpython => hostpython2}/ssize-t-max.patch | 0 recipes/{hostpython => hostpython2}/static-_sqlite3.patch | 0 recipes/{python => python2}/ModulesSetup | 0 recipes/{python => python2}/ModulesSetup.mobile | 0 recipes/{python => python2}/ModulesSetup.openssl | 0 recipes/{python => python2}/__init__.py | 0 recipes/{python => python2}/_scproxy.py | 0 recipes/{python => python2}/ctypes_duplicate.patch | 0 recipes/{python => python2}/ctypes_duplicate_longdouble.patch | 0 recipes/{python => python2}/dynload.patch | 0 recipes/{python => python2}/environ_symbol_fix.patch | 0 recipes/{python => python2}/ipv6.patch | 0 recipes/{python => python2}/posixmodule.patch | 0 recipes/{python => python2}/pyconfig.patch | 0 recipes/{python => python2}/setuppath.patch | 0 recipes/{python => python2}/ssize-t-max.patch | 0 recipes/{python => python2}/static-_sqlite3.patch | 0 recipes/{python => python2}/xcompile.patch | 0 23 files changed, 0 insertions(+), 0 deletions(-) rename recipes/{hostpython => hostpython2}/ModulesSetup (100%) rename recipes/{hostpython => hostpython2}/ModulesSetup.openssl (100%) rename recipes/{hostpython => hostpython2}/__init__.py (100%) rename recipes/{hostpython => hostpython2}/_scproxy.py (100%) rename recipes/{hostpython => hostpython2}/dynload.patch (100%) rename recipes/{hostpython => hostpython2}/ssize-t-max.patch (100%) rename recipes/{hostpython => hostpython2}/static-_sqlite3.patch (100%) rename recipes/{python => python2}/ModulesSetup (100%) rename recipes/{python => python2}/ModulesSetup.mobile (100%) rename recipes/{python => python2}/ModulesSetup.openssl (100%) rename recipes/{python => python2}/__init__.py (100%) rename recipes/{python => python2}/_scproxy.py (100%) rename recipes/{python => python2}/ctypes_duplicate.patch (100%) rename recipes/{python => python2}/ctypes_duplicate_longdouble.patch (100%) rename recipes/{python => python2}/dynload.patch (100%) rename recipes/{python => python2}/environ_symbol_fix.patch (100%) rename recipes/{python => python2}/ipv6.patch (100%) rename recipes/{python => python2}/posixmodule.patch (100%) rename recipes/{python => python2}/pyconfig.patch (100%) rename recipes/{python => python2}/setuppath.patch (100%) rename recipes/{python => python2}/ssize-t-max.patch (100%) rename recipes/{python => python2}/static-_sqlite3.patch (100%) rename recipes/{python => python2}/xcompile.patch (100%) diff --git a/recipes/hostpython/ModulesSetup b/recipes/hostpython2/ModulesSetup similarity index 100% rename from recipes/hostpython/ModulesSetup rename to recipes/hostpython2/ModulesSetup diff --git a/recipes/hostpython/ModulesSetup.openssl b/recipes/hostpython2/ModulesSetup.openssl similarity index 100% rename from recipes/hostpython/ModulesSetup.openssl rename to recipes/hostpython2/ModulesSetup.openssl diff --git a/recipes/hostpython/__init__.py b/recipes/hostpython2/__init__.py similarity index 100% rename from recipes/hostpython/__init__.py rename to recipes/hostpython2/__init__.py diff --git a/recipes/hostpython/_scproxy.py b/recipes/hostpython2/_scproxy.py similarity index 100% rename from recipes/hostpython/_scproxy.py rename to recipes/hostpython2/_scproxy.py diff --git a/recipes/hostpython/dynload.patch b/recipes/hostpython2/dynload.patch similarity index 100% rename from recipes/hostpython/dynload.patch rename to recipes/hostpython2/dynload.patch diff --git a/recipes/hostpython/ssize-t-max.patch b/recipes/hostpython2/ssize-t-max.patch similarity index 100% rename from recipes/hostpython/ssize-t-max.patch rename to recipes/hostpython2/ssize-t-max.patch diff --git a/recipes/hostpython/static-_sqlite3.patch b/recipes/hostpython2/static-_sqlite3.patch similarity index 100% rename from recipes/hostpython/static-_sqlite3.patch rename to recipes/hostpython2/static-_sqlite3.patch diff --git a/recipes/python/ModulesSetup b/recipes/python2/ModulesSetup similarity index 100% rename from recipes/python/ModulesSetup rename to recipes/python2/ModulesSetup diff --git a/recipes/python/ModulesSetup.mobile b/recipes/python2/ModulesSetup.mobile similarity index 100% rename from recipes/python/ModulesSetup.mobile rename to recipes/python2/ModulesSetup.mobile diff --git a/recipes/python/ModulesSetup.openssl b/recipes/python2/ModulesSetup.openssl similarity index 100% rename from recipes/python/ModulesSetup.openssl rename to recipes/python2/ModulesSetup.openssl diff --git a/recipes/python/__init__.py b/recipes/python2/__init__.py similarity index 100% rename from recipes/python/__init__.py rename to recipes/python2/__init__.py diff --git a/recipes/python/_scproxy.py b/recipes/python2/_scproxy.py similarity index 100% rename from recipes/python/_scproxy.py rename to recipes/python2/_scproxy.py diff --git a/recipes/python/ctypes_duplicate.patch b/recipes/python2/ctypes_duplicate.patch similarity index 100% rename from recipes/python/ctypes_duplicate.patch rename to recipes/python2/ctypes_duplicate.patch diff --git a/recipes/python/ctypes_duplicate_longdouble.patch b/recipes/python2/ctypes_duplicate_longdouble.patch similarity index 100% rename from recipes/python/ctypes_duplicate_longdouble.patch rename to recipes/python2/ctypes_duplicate_longdouble.patch diff --git a/recipes/python/dynload.patch b/recipes/python2/dynload.patch similarity index 100% rename from recipes/python/dynload.patch rename to recipes/python2/dynload.patch diff --git a/recipes/python/environ_symbol_fix.patch b/recipes/python2/environ_symbol_fix.patch similarity index 100% rename from recipes/python/environ_symbol_fix.patch rename to recipes/python2/environ_symbol_fix.patch diff --git a/recipes/python/ipv6.patch b/recipes/python2/ipv6.patch similarity index 100% rename from recipes/python/ipv6.patch rename to recipes/python2/ipv6.patch diff --git a/recipes/python/posixmodule.patch b/recipes/python2/posixmodule.patch similarity index 100% rename from recipes/python/posixmodule.patch rename to recipes/python2/posixmodule.patch diff --git a/recipes/python/pyconfig.patch b/recipes/python2/pyconfig.patch similarity index 100% rename from recipes/python/pyconfig.patch rename to recipes/python2/pyconfig.patch diff --git a/recipes/python/setuppath.patch b/recipes/python2/setuppath.patch similarity index 100% rename from recipes/python/setuppath.patch rename to recipes/python2/setuppath.patch diff --git a/recipes/python/ssize-t-max.patch b/recipes/python2/ssize-t-max.patch similarity index 100% rename from recipes/python/ssize-t-max.patch rename to recipes/python2/ssize-t-max.patch diff --git a/recipes/python/static-_sqlite3.patch b/recipes/python2/static-_sqlite3.patch similarity index 100% rename from recipes/python/static-_sqlite3.patch rename to recipes/python2/static-_sqlite3.patch diff --git a/recipes/python/xcompile.patch b/recipes/python2/xcompile.patch similarity index 100% rename from recipes/python/xcompile.patch rename to recipes/python2/xcompile.patch From 811cbd48a7275f1b8057cb54cba404b5e64bf2ba Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Fri, 2 Nov 2018 11:44:25 +0100 Subject: [PATCH 29/42] add alias for hostpython/python, that point to either 2 or 3 version depending of the previous compiled state. This allows the recipe to point on an versionless python. --- recipes/hostpython.py | 15 ++++++ recipes/hostpython2/__init__.py | 8 +-- recipes/hostpython3/__init__.py | 2 + recipes/ios/__init__.py | 5 +- recipes/kivy/__init__.py | 5 +- recipes/pyobjus/__init__.py | 5 +- recipes/python.py | 15 ++++++ recipes/python2/__init__.py | 18 +++---- recipes/python3/__init__.py | 10 ++-- toolchain.py | 87 +++++++++++++++++++++++++++------ 10 files changed, 130 insertions(+), 40 deletions(-) create mode 100644 recipes/hostpython.py create mode 100644 recipes/python.py diff --git a/recipes/hostpython.py b/recipes/hostpython.py new file mode 100644 index 0000000..3291cc3 --- /dev/null +++ b/recipes/hostpython.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +from toolchain import Recipe + +class HostpythonAliasRecipe(Recipe): + is_alias = True + + def init_after_import(self, ctx): + hostpython = ctx.state.get("hostpython") + if not hostpython: + print("WARNING: no hostpython set yet, so you need to specify") + print("WARNING: either hostpython2 or hostpython3 in your deps") + else: + self.depends = [hostpython] + +recipe = HostpythonAliasRecipe() diff --git a/recipes/hostpython2/__init__.py b/recipes/hostpython2/__init__.py index 3281a00..bccb7e8 100644 --- a/recipes/hostpython2/__init__.py +++ b/recipes/hostpython2/__init__.py @@ -5,7 +5,7 @@ import sh import shutil -class HostpythonRecipe(Recipe): +class Hostpython2Recipe(Recipe): version = "2.7.1" url = "https://www.python.org/ftp/python/{version}/Python-{version}.tar.bz2" depends = ["hostlibffi"] @@ -13,7 +13,9 @@ class HostpythonRecipe(Recipe): archs = ["x86_64"] def init_with_ctx(self, ctx): - super(HostpythonRecipe, self).init_with_ctx(ctx) + super(Hostpython2Recipe, self).init_with_ctx(ctx) + self.set_hostpython(self, 2.7) + self.ctx.so_suffix = ".so" self.ctx.hostpython = join(self.ctx.dist_dir, "hostpython", "bin", "python") self.ctx.hostpgen = join(self.ctx.dist_dir, "hostpython", "bin", "pgen") print("Global: hostpython located at {}".format(self.ctx.hostpython)) @@ -110,4 +112,4 @@ class HostpythonRecipe(Recipe): join(self.ctx.dist_dir, "hostpython", "bin", "pgen")) -recipe = HostpythonRecipe() +recipe = Hostpython2Recipe() diff --git a/recipes/hostpython3/__init__.py b/recipes/hostpython3/__init__.py index 7d99b86..740dcc9 100644 --- a/recipes/hostpython3/__init__.py +++ b/recipes/hostpython3/__init__.py @@ -14,6 +14,8 @@ class Hostpython3Recipe(Recipe): def init_with_ctx(self, ctx): super(Hostpython3Recipe, self).init_with_ctx(ctx) + self.set_hostpython(self, 3.7) + self.ctx.so_suffix = ".cpython-37m-darwin.so" self.ctx.hostpython = join(self.ctx.dist_dir, "hostpython3", "bin", "python") self.ctx.hostpgen = join(self.ctx.dist_dir, "hostpython3", "bin", "pgen") print("Global: hostpython located at {}".format(self.ctx.hostpython)) diff --git a/recipes/ios/__init__.py b/recipes/ios/__init__.py index af4264d..33a6678 100644 --- a/recipes/ios/__init__.py +++ b/recipes/ios/__init__.py @@ -9,9 +9,8 @@ class IosRecipe(CythonRecipe): pbx_frameworks = ["MessageUI", "CoreMotion", "UIKit"] def install(self): - self.install_python_package(name="ios.so", is_dir=False) + self.install_python_package( + name=self.so_filename("ios"), is_dir=False) recipe = IosRecipe() - - diff --git a/recipes/kivy/__init__.py b/recipes/kivy/__init__.py index 9b9b19d..559e1df 100644 --- a/recipes/kivy/__init__.py +++ b/recipes/kivy/__init__.py @@ -6,8 +6,8 @@ class KivyRecipe(CythonRecipe): version = "1.10.1" url = "https://github.com/kivy/kivy/archive/{version}.zip" library = "libkivy.a" - depends = ["python", "sdl2", "sdl2_image", "sdl2_mixer", "sdl2_ttf", "ios", - "pyobjus"] + depends = ["sdl2", "sdl2_image", "sdl2_mixer", "sdl2_ttf", "ios", + "pyobjus", "python"] pbx_frameworks = ["OpenGLES", "Accelerate"] pre_build_ext = True @@ -40,4 +40,3 @@ class KivyRecipe(CythonRecipe): recipe = KivyRecipe() - diff --git a/recipes/pyobjus/__init__.py b/recipes/pyobjus/__init__.py index 639b838..210aad4 100644 --- a/recipes/pyobjus/__init__.py +++ b/recipes/pyobjus/__init__.py @@ -18,8 +18,9 @@ class PyobjusRecipe(CythonRecipe): def cythonize_build(self): # don't use the cythonize, pyobjus don't support method rewriting + pyver = "-{}".format(self.ctx.python_major) shprint(sh.find, self.build_dir, "-iname", "*.pyx", - "-exec", "cython", "{}", ";") + "-exec", "cython", pyver, "{}", ";") # ffi is installed somewhere else, this include doesn't work # XXX ideally, we need to fix libffi installation... shprint(sh.sed, @@ -28,5 +29,3 @@ class PyobjusRecipe(CythonRecipe): "pyobjus/pyobjus.c") recipe = PyobjusRecipe() - - diff --git a/recipes/python.py b/recipes/python.py new file mode 100644 index 0000000..359f03f --- /dev/null +++ b/recipes/python.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +from toolchain import Recipe + +class PythonAliasRecipe(Recipe): + is_alias = True + + def init_after_import(self, ctx): + python = ctx.state.get("python") + if not python: + print("WARNING: no python set yet, so you need to specify") + print("WARNING: either python2 or python3 in your deps") + else: + self.depends = [python] + +recipe = PythonAliasRecipe() diff --git a/recipes/python2/__init__.py b/recipes/python2/__init__.py index 24cde16..ac253e6 100644 --- a/recipes/python2/__init__.py +++ b/recipes/python2/__init__.py @@ -4,21 +4,21 @@ import sh import os -class PythonRecipe(Recipe): +class Python2Recipe(Recipe): version = "2.7.1" url = "https://www.python.org/ftp/python/{version}/Python-{version}.tar.bz2" - depends = ["hostpython", "libffi", ] + depends = ["hostpython2", "libffi"] optional_depends = ["openssl"] library = "libpython2.7.a" pbx_libraries = ["libz", "libbz2", "libsqlite3"] def init_with_ctx(self, ctx): - super(PythonRecipe, self).init_with_ctx(ctx) - self.ctx.python_ver_dir = "python2.7" - self.ctx.python_prefix = join(ctx.dist_dir, "root", "python") - self.ctx.site_packages_dir = join( - ctx.dist_dir, "root", "python", "lib", ctx.python_ver_dir, - "site-packages") + super(Python2Recipe, self).init_with_ctx(ctx) + self.set_python(self, 2.7) + ctx.python_ver_dir = "python2.7" + ctx.python_prefix = join(ctx.dist_dir, "root", "python") + ctx.site_packages_dir = join( + ctx.python_prefix, "lib", ctx.python_ver_dir, "site-packages") def prebuild_arch(self, arch): # common to all archs @@ -149,4 +149,4 @@ class PythonRecipe(Recipe): os.chdir(oldpwd) -recipe = PythonRecipe() +recipe = Python2Recipe() diff --git a/recipes/python3/__init__.py b/recipes/python3/__init__.py index 41ae1d1..0ad068a 100644 --- a/recipes/python3/__init__.py +++ b/recipes/python3/__init__.py @@ -15,11 +15,11 @@ class Python3Recipe(Recipe): def init_with_ctx(self, ctx): super(Python3Recipe, self).init_with_ctx(ctx) - self.ctx.python_ver_dir = "python3.7" - self.ctx.python_prefix = join(ctx.dist_dir, "root", "python") - self.ctx.site_packages_dir = join( - ctx.dist_dir, "root", "python", "lib", ctx.python_ver_dir, - "site-packages") + self.set_python(self, 3.7) + ctx.python_ver_dir = "python3.7" + ctx.python_prefix = join(ctx.dist_dir, "root", "python3") + ctx.site_packages_dir = join( + ctx.python_prefix, "lib", ctx.python_ver_dir, "site-packages") def prebuild_arch(self, arch): # common to all archs diff --git a/toolchain.py b/toolchain.py index 80a3961..922f85f 100755 --- a/toolchain.py +++ b/toolchain.py @@ -306,6 +306,7 @@ class Context(object): cython = None sdkver = None sdksimver = None + so_suffix = None # set by one of the hostpython def __init__(self): super(Context, self).__init__() @@ -413,20 +414,30 @@ class Context(object): return "IDEBuildOperationMaxNumberOfConcurrentCompileTasks={}".format(self.num_cores) + class Recipe(object): - version = None - url = None - archs = [] - depends = [] - optional_depends = [] - library = None - libraries = [] - include_dir = None - include_per_arch = False - frameworks = [] - sources = [] - pbx_frameworks = [] - pbx_libraries = [] + props = { + "is_alias": False, + "version": None, + "url": None, + "archs": [], + "depends": [], + "optional_depends": [], + "library": None, + "libraries": [], + "include_dir": None, + "include_per_arch": False, + "frameworks": [], + "sources": [], + "pbx_frameworks": [], + "pbx_libraries": [] + } + + def __new__(cls): + for prop, value in cls.props.items(): + if not hasattr(cls, prop): + setattr(cls, prop, value) + return super(Recipe, cls).__new__(cls) # API available for recipes def download_file(self, url, filename, cwd=None): @@ -560,6 +571,12 @@ class Recipe(object): """ return join(self.ctx.include_dir, "common", self.name) + def so_filename(self, name): + """Return the filename of a library with the appropriate so suffix + (.so for Python 2.7, .cpython-37m-darwin for Python 3.7) + """ + return "{}{}".format(name, self.ctx.so_suffix) + @property def name(self): modname = self.__class__.__module__ @@ -619,6 +636,37 @@ class Recipe(object): arch = self.filtered_archs[0] return arch.get_env() + def set_hostpython(self, instance, version): + state = self.ctx.state + hostpython = state.get("hostpython") + if hostpython is None: + state["hostpython"] = instance.name + state.sync() + elif hostpython != instance.name: + print("ERROR: Wanted to use {}".format(instance.name)) + print("ERROR: but hostpython is already provided by {}.".format( + hostpython)) + print("ERROR: You can have only one hostpython version compiled") + sys.exit(1) + self.ctx.python_major = int(version) + self.ctx.hostpython_ver = version + self.ctx.hostpython_recipe = instance + + def set_python(self, instance, version): + state = self.ctx.state + python = state.get("python") + if python is None: + state["python"] = instance.name + state.sync() + elif python != instance.name: + print("ERROR: Wanted to use {}".format(instance.name)) + print("ERROR: but python is already provided by {}.".format( + python)) + print("ERROR: You can have only one python version compiled") + sys.exit(1) + self.ctx.python_ver = version + self.ctx.python_recipe = instance + @property def archive_root(self): key = "{}.archive_root".format(self.name) @@ -649,6 +697,12 @@ class Recipe(object): raise ValueError("Invalid path passed into {}".format(envname)) return d + def init_after_import(cls, ctx): + """This can be used to dynamically set some variables + depending of the state + """ + pass + @cache_execution def download(self): key = "{}.archive_root".format(self.name) @@ -875,6 +929,7 @@ class Recipe(object): mod = importlib.import_module("recipes.{}".format(name)) recipe = mod.recipe recipe.recipe_dir = join(ctx.root_dir, "recipes", name) + recipe.init_after_import(ctx) if version: recipe.version = version @@ -916,7 +971,7 @@ class PythonRecipe(Recipe): "--prefix", iosbuild, _env=env) dest_dir = join(self.ctx.site_packages_dir, name) - self.remove_junk(iosbuild) + #self.remove_junk(iosbuild) if is_dir: if exists(dest_dir): shutil.rmtree(dest_dir) @@ -944,6 +999,7 @@ class CythonRecipe(PythonRecipe): filename = filename[len(self.build_dir) + 1:] print("Cythonize {}".format(filename)) cmd = sh.Command(join(self.ctx.root_dir, "tools", "cythonize.py")) + hostpython = self.ctx.state.get("hostpython") shprint(cmd, filename) def cythonize_build(self): @@ -1021,6 +1077,9 @@ def build_recipes(names, ctx): build_order = list(graph.find_order()) print("Build order is {}".format(build_order)) recipes = [Recipe.get_recipe(name, ctx) for name in build_order] + recipes = [recipe for recipe in recipes if not recipe.is_alias] + recipes_order = [recipe.name for recipe in recipes] + print("Recipe order is {}".format(recipes_order)) for recipe in recipes: recipe.init_with_ctx(ctx) for recipe in recipes: From 7c8a2c6c4b90bce60e9f4725feb5b3af5c1441e2 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Fri, 9 Nov 2018 17:54:56 +0100 Subject: [PATCH 30/42] rework toolchain for python 3, new possibility to have a specific name for the include directory (like the recipe libffi install in ffi directory, not libffi), and new pyobjus recipe (works with new-ios-toolchain branch). --- recipes/ios/src/ios.pyx | 14 ++-- recipes/libffi/__init__.py | 1 + recipes/pyobjus/__init__.py | 22 +----- recipes/python3/ModulesSetup | 93 ++++++++++++++++++++++++++ recipes/python3/ModulesSetup.mobile | 2 + recipes/python3/__init__.py | 80 +++++++++++++--------- recipes/python3/ctypes_duplicate.patch | 17 +++++ recipes/python3/dynload.patch | 25 +++++++ tests/test_python3/main.m | 33 ++++++--- tests/test_python3/main.py | 53 +++++++++++++++ toolchain.py | 11 ++- 11 files changed, 278 insertions(+), 73 deletions(-) create mode 100644 recipes/python3/ModulesSetup create mode 100644 recipes/python3/ModulesSetup.mobile create mode 100644 recipes/python3/ctypes_duplicate.patch create mode 100644 recipes/python3/dynload.patch diff --git a/recipes/ios/src/ios.pyx b/recipes/ios/src/ios.pyx index 323f128..08d2009 100644 --- a/recipes/ios/src/ios.pyx +++ b/recipes/ios/src/ios.pyx @@ -29,7 +29,7 @@ cdef void _send_email_done(char *status, void *data): class IOSWebView(object): def open(self, url, width, height): open_url_wbv(url, width, height) - + def open_url_wbv(url, width, height): ''' @@ -66,8 +66,12 @@ class IosBrowser(object): open_url(url) import webbrowser -webbrowser.register('ios', IosBrowser, None, -1) - +try: + # python 2 + webbrowser.register('ios', IosBrowser, None, -1) +except: + # python 3 + webbrowser.register('ios', IosBrowser, None, preferred=True) # # API # @@ -119,7 +123,7 @@ def send_email(subject, text, mimetype=None, filename=None, filename_alias=None, Example for sending a simple hello world:: - ios.send_email('This is my subject', + ios.send_email('This is my subject', 'Hello you!\n\nThis is an hello world.') Send a mail with an attachment:: @@ -222,7 +226,7 @@ class IOSKeyboard(object): def __init__(self, **kwargs): super(IOSKeyboard, self).__init__() NSNotificationCenter.defaultCenter().addObserver_selector_name_object_(self, selector("keyboardWillShow"), "UIKeyboardWillShowNotification", None) - NSNotificationCenter.defaultCenter().addObserver_selector_name_object_(self, selector("keyboardDidHide"), "UIKeyboardDidHideNotification", None) + NSNotificationCenter.defaultCenter().addObserver_selector_name_object_(self, selector("keyboardDidHide"), "UIKeyboardDidHideNotification", None) @protocol('KeyboardDelegates') def keyboardWillShow(self, notification): diff --git a/recipes/libffi/__init__.py b/recipes/libffi/__init__.py index a24bc00..a9f3cac 100644 --- a/recipes/libffi/__init__.py +++ b/recipes/libffi/__init__.py @@ -10,6 +10,7 @@ class LibffiRecipe(Recipe): library = "build/Release-{arch.sdk}/libffi.a" include_per_arch = True include_dir = "build_{arch.sdk}-{arch.arch}/include" + include_name = "ffi" archs = ["x86_64", "armv7", "arm64"] def prebuild_arch(self, arch): diff --git a/recipes/pyobjus/__init__.py b/recipes/pyobjus/__init__.py index 210aad4..c5cd0dd 100644 --- a/recipes/pyobjus/__init__.py +++ b/recipes/pyobjus/__init__.py @@ -1,7 +1,4 @@ -from toolchain import CythonRecipe, shprint -from os.path import join -import sh - +from toolchain import CythonRecipe class PyobjusRecipe(CythonRecipe): version = "master" @@ -10,22 +7,5 @@ class PyobjusRecipe(CythonRecipe): depends = ["python"] pre_build_ext = True - def get_recipe_env(self, arch): - env = super(PyobjusRecipe, self).get_recipe_env(arch) - env["CC"] += " -I{}".format( - join(self.ctx.dist_dir, "include", arch.arch, "libffi")) - return env - - def cythonize_build(self): - # don't use the cythonize, pyobjus don't support method rewriting - pyver = "-{}".format(self.ctx.python_major) - shprint(sh.find, self.build_dir, "-iname", "*.pyx", - "-exec", "cython", pyver, "{}", ";") - # ffi is installed somewhere else, this include doesn't work - # XXX ideally, we need to fix libffi installation... - shprint(sh.sed, - "-i.bak", - "s/ffi\///g", - "pyobjus/pyobjus.c") recipe = PyobjusRecipe() diff --git a/recipes/python3/ModulesSetup b/recipes/python3/ModulesSetup new file mode 100644 index 0000000..ef5923f --- /dev/null +++ b/recipes/python3/ModulesSetup @@ -0,0 +1,93 @@ +##################################################################### +# Static compilation instructions for all binary modules. +##################################################################### + +_asyncio _asynciomodule.c +_bisect _bisectmodule.c +_blake2 _blake2/blake2module.c _blake2/blake2b_impl.c _blake2/blake2s_impl.c +# _bz2 _bz2module.c -I$(srcdir)/../bzip2/include -L$(srcdir)/../Support/BZip2 -lbz2 +_codecs_cn cjkcodecs/_codecs_cn.c +_codecs_hk cjkcodecs/_codecs_hk.c +_codecs_iso2022 cjkcodecs/_codecs_iso2022.c +_codecs_jp cjkcodecs/_codecs_jp.c +_codecs_kr cjkcodecs/_codecs_kr.c +_codecs_tw cjkcodecs/_codecs_tw.c +_contextvars _contextvarsmodule.c +_crypt _cryptmodule.c +_csv _csv.c +_datetime _datetimemodule.c +_elementtree _elementtree.c \ + -I$(srcdir)/Modules/expat + -DHAVE_EXPAT_CONFIG_H -DUSE_PYEXPAT_CAPI +_hashlib _hashopenssl.c -lssl -DUSE_SSL +_heapq _heapqmodule.c +_json _json.c +_lsprof _lsprof.o rotatingtree.c +# _lzma _lzmamodule.c -I$(srcdir)/../xz/include -L$(srcdir)/../Support/XZ -llzma +_md5 md5module.c +_multibytecodec cjkcodecs/multibytecodec.c +# _multiprocessing _multiprocessing/multiprocessing.c _multiprocessing/semaphore.c +_opcode _opcode.c +_queue _queuemodule.c +_pickle _pickle.c +# _posixsubprocess _posixsubprocess.c +_random _randommodule.c +_sha1 sha1module.c +_sha3 _sha3/sha3module.c +_sha256 sha256module.c +_sha512 sha512module.c +_socket socketmodule.c +_sqlite3 -I$(srcdir)/Modules/_sqlite -DMODULE_NAME='\"sqlite3\"' -DSQLITE_OMIT_LOAD_EXTENSION -lsqlite3 \ + _sqlite/cache.c \ + _sqlite/connection.c \ + _sqlite/cursor.c \ + _sqlite/microprotocols.c \ + _sqlite/module.c \ + _sqlite/prepare_protocol.c \ + _sqlite/row.c \ + _sqlite/statement.c \ + _sqlite/util.c +_ssl _ssl.c -lssl -DUSE_SSL +_struct _struct.c +array arraymodule.c +audioop audioop.c +binascii binascii.c +cmath cmathmodule.c _math.c +fcntl fcntlmodule.c +grp grpmodule.c +math mathmodule.c +# mmap mmapmodule.c +parser parsermodule.c +pyexpat expat/xmlparse.c \ + expat/xmlrole.c \ + expat/xmltok.c \ + pyexpat.c \ + -I$(srcdir)/Modules/expat \ + -DHAVE_EXPAT_CONFIG_H -DUSE_PYEXPAT_CAPI -DXML_DEV_URANDOM +resource resource.c +select selectmodule.c +syslog syslogmodule.c +termios termios.c +unicodedata unicodedata.c +zlib zlibmodule.c -I$(prefix)/include -lz + +##################################################################### +# Testing modules +##################################################################### +_ctypes_test _ctypes/_ctypes_test.c +_testbuffer _testbuffer.c +_testcapi _testcapimodule.c +_testimportmultiple _testimportmultiple.c + +##################################################################### +# Modules that require additional frameworks +##################################################################### +#_curses _cursesmodule.c -lcurses -ltermcap +#_curses_panel _curses_panel.c -lpanel -lncurses +#_dbm _dbmmodule.c +#_gdbm _gdbmmodule.c -I/usr/local/include -L/usr/local/lib -lgdbm +#_tkinter _tkinter.c tkappinit.c -DWITH_APPINIT -I... -L... +#nis nismodule.c -lnsl +#ossaudiodev +#readline readline.c -lreadline -ltermcap +#spwd spwdmodule.c diff --git a/recipes/python3/ModulesSetup.mobile b/recipes/python3/ModulesSetup.mobile new file mode 100644 index 0000000..826bf1c --- /dev/null +++ b/recipes/python3/ModulesSetup.mobile @@ -0,0 +1,2 @@ +# Ctypes +_ctypes _ctypes/_ctypes.c _ctypes/callbacks.c _ctypes/callproc.c _ctypes/stgdict.c _ctypes/cfield.c -I$(srcdir)/../../build/include/ffi diff --git a/recipes/python3/__init__.py b/recipes/python3/__init__.py index 0ad068a..231c519 100644 --- a/recipes/python3/__init__.py +++ b/recipes/python3/__init__.py @@ -8,8 +8,7 @@ import os class Python3Recipe(Recipe): version = "3.7.1" url = "https://www.python.org/ftp/python/{version}/Python-{version}.tgz" - depends = ["hostpython3", "libffi", ] - optional_depends = ["openssl"] + depends = ["hostpython3", "libffi", "openssl"] library = "libpython3.7m.a" pbx_libraries = ["libz", "libbz2", "libsqlite3"] @@ -25,19 +24,10 @@ class Python3Recipe(Recipe): # common to all archs if self.has_marker("patched"): return - # self.apply_patch("ssize-t-max.patch") - # self.apply_patch("dynload.patch") - # self.apply_patch("static-_sqlite3.patch") - shutil.copy("Modules/Setup.dist", "Modules/Setup") + self.apply_patch("dynload.patch") + self.copy_file("ModulesSetup", "Modules/Setup.local") + self.append_file("ModulesSetup.mobile", "Modules/Setup.local") self.apply_patch("xcompile.patch") - # self.copy_file("_scproxy.py", "Lib/_scproxy.py") - # self.apply_patch("xcompile.patch") - # self.apply_patch("setuppath.patch") - # self.append_file("ModulesSetup.mobile", "Modules/Setup.local") - # self.apply_patch("ipv6.patch") - # if "openssl.build_all" in self.ctx.state: - # self.append_file("ModulesSetup.openssl", "Modules/Setup.local") - # self.apply_patch("posixmodule.patch") self.set_marker("patched") def get_build_env(self, arch): @@ -55,14 +45,13 @@ class Python3Recipe(Recipe): py_arch = "arm" elif py_arch == "arm64": py_arch = "aarch64" - prefix = join(self.ctx.dist_dir, "python3") + prefix = join(self.ctx.dist_dir, "root", "python3") shprint(configure, "CC={}".format(build_env["CC"]), "LD={}".format(build_env["LD"]), "CFLAGS={}".format(build_env["CFLAGS"]), "LDFLAGS={} -undefined dynamic_lookup".format(build_env["LDFLAGS"]), # "--without-pymalloc", - # "--disable-toolbox-glue", "ac_cv_file__dev_ptmx=yes", "ac_cv_file__dev_ptc=no", "ac_cv_little_endian_double=yes", @@ -93,20 +82,14 @@ class Python3Recipe(Recipe): "--host={}-apple-ios".format(py_arch), "--build=x86_64-apple-darwin", "--prefix={}".format(prefix), - "--exec-prefix={}".format(prefix), "--without-ensurepip", - # "--with-system-ffi", + "--with-system-ffi", # "--without-doc-strings", "--enable-ipv6", _env=build_env) - # self._patch_pyconfig() - # self.apply_patch("ctypes_duplicate.patch") - # self.apply_patch("ctypes_duplicate_longdouble.patch") + self.apply_patch("ctypes_duplicate.patch") shprint(sh.make, self.ctx.concurrent_make) - # "HOSTPYTHON={}".format(self.ctx.hostpython), - # "HOSTPGEN={}".format(self.ctx.hostpgen)) - # "CROSS_COMPILE_TARGET=yes", def install(self): arch = list(self.filtered_archs)[0] @@ -117,6 +100,7 @@ class Python3Recipe(Recipe): "install", "prefix={}".format(join(self.ctx.dist_dir, "root", "python3")), _env=build_env) + # os.execve("/bin/bash", ["/bin/bash"], os.environ) self.reduce_python() def reduce_python(self): @@ -125,7 +109,10 @@ class Python3Recipe(Recipe): try: print("Remove files unlikely to be used") os.chdir(join(self.ctx.dist_dir, "root", "python3")) - sh.rm("-rf", "share") + # os.execve("/bin/bash", ["/bin/bash"], env=os.environ) + sh.rm("-rf", "bin", "share") + + # platform binaries and configuration os.chdir(join( self.ctx.dist_dir, "root", "python3", "lib", "python3.7", "config-3.7m-darwin")) @@ -134,15 +121,42 @@ class Python3Recipe(Recipe): sh.rm("config.c.in") sh.rm("makesetup") sh.rm("install-sh") - os.chdir(join(self.ctx.dist_dir, "root", "python3", "lib", "python3.7")) - # sh.find(".", "-iname", "*.pyc", "-exec", "rm", "{}", ";") - # sh.find(".", "-iname", "*.py", "-exec", "rm", "{}", ";") - #sh.find(".", "-iname", "test*", "-exec", "rm", "-rf", "{}", ";") - sh.rm("-rf", "wsgiref", "curses", "idlelib", "lib2to3") - # now create the zip. - print("Create a stdlib.zip") - sh.zip("-r", "../stdlib.zip", sh.glob("*")) + # cleanup pkgconfig and compiled lib + os.chdir(join(self.ctx.dist_dir, "root", "python3", "lib")) + sh.rm("-rf", "pkgconfig") + sh.rm("-f", "libpython3.7m.a") + + # cleanup python libraries + os.chdir(join( + self.ctx.dist_dir, "root", "python3", "lib", "python3.7")) + sh.rm("-rf", "wsgiref", "curses", "idlelib", "lib2to3", + "ensurepip", "turtledemo", "lib-dynload", "venv", + "pydoc_data") + sh.find(".", "-path", "*/test*/*", "-delete") + sh.find(".", "-name", "*.exe", "-type", "f", "-delete") + sh.find(".", "-name", "test*", "-type", "d", "-delete") + sh.find(".", "-iname", "*.pyc", "-delete") + sh.find(".", "-path", "*/__pycache__/*", "-delete") + sh.find(".", "-name", "__pycache__", "-type", "d", "-delete") + + # now precompile to Python bytecode + hostpython = sh.Command(self.ctx.hostpython) + shprint(hostpython, "-m", "compileall", "-f", "-b") + # sh.find(".", "-iname", "*.py", "-delete") + + # some pycache are recreated after compileall + sh.find(".", "-path", "*/__pycache__/*", "-delete") + sh.find(".", "-name", "__pycache__", "-type", "d", "-delete") + + # create the lib zip + print("Create a python3.7.zip") + sh.mv("config-3.7m-darwin", "..") + sh.mv("site-packages", "..") + sh.zip("-r", "../python37.zip", sh.glob("*")) + sh.rm("-rf", sh.glob("*")) + sh.mv("../config-3.7m-darwin", ".") + sh.mv("../site-packages", ".") finally: os.chdir(oldpwd) diff --git a/recipes/python3/ctypes_duplicate.patch b/recipes/python3/ctypes_duplicate.patch new file mode 100644 index 0000000..b2231e9 --- /dev/null +++ b/recipes/python3/ctypes_duplicate.patch @@ -0,0 +1,17 @@ +--- Python-3.7.1/Modules/_ctypes/cfield.c-old 2018-11-03 13:47:40.000000000 +0100 ++++ Python-3.7.1/Modules/_ctypes/cfield.c 2018-11-03 13:48:14.000000000 +0100 +@@ -1633,6 +1633,7 @@ + } ffi_type; + */ + ++#if 0 + /* align and size are bogus for void, but they must not be zero */ + ffi_type ffi_type_void = { 1, 1, FFI_TYPE_VOID }; + +@@ -1660,4 +1661,6 @@ + + ffi_type ffi_type_pointer = { sizeof(void *), VOID_P_ALIGN, FFI_TYPE_POINTER }; + ++#endif ++ + /*---------------- EOF ----------------*/ diff --git a/recipes/python3/dynload.patch b/recipes/python3/dynload.patch new file mode 100644 index 0000000..a5e080f --- /dev/null +++ b/recipes/python3/dynload.patch @@ -0,0 +1,25 @@ +--- Python-3.7.1/Python/dynload_shlib.c 2018-10-20 08:04:19.000000000 +0200 ++++ Python-3.7.1/Python/dynload_shlib.c 2018-11-02 14:23:15.000000000 +0100 +@@ -72,6 +72,16 @@ + PyOS_snprintf(funcname, sizeof(funcname), + LEAD_UNDERSCORE "%.20s_%.200s", prefix, shortname); + ++ /* On IOS, dlopen crash as soon as we try to open one of our library. ++ * Instead, we have done a redirection of linking to convert our .so into a ++ * .a. Then the main executable is linked with theses symbol. So, instead ++ * of trying to dlopen, directly do the dlsym. ++ * -- Mathieu ++ */ ++ return (dl_funcptr) dlsym(RTLD_SELF, funcname); ++ ++#if 0 ++ + if (fp != NULL) { + int i; + struct _Py_stat_struct status; +@@ -126,4 +136,5 @@ + handles[nhandles++].handle = handle; + p = (dl_funcptr) dlsym(handle, funcname); + return p; ++#endif + } diff --git a/tests/test_python3/main.m b/tests/test_python3/main.m index 873bd8b..e233f0b 100644 --- a/tests/test_python3/main.m +++ b/tests/test_python3/main.m @@ -25,9 +25,10 @@ int main(int argc, char *argv[]) { // putenv("PYTHONOPTIMIZE=2"); putenv("PYTHONDONTWRITEBYTECODE=1"); putenv("PYTHONNOUSERSITE=1"); -// putenv("PYTHONPATH=."); + putenv("PYTHONPATH=."); // putenv("PYTHONVERBOSE=1"); putenv("PYTHONUNBUFFERED=1"); +// putenv("PYOBJUS_DEBUG=1"); // Kivy environment to prefer some implementation on iOS platform putenv("KIVY_BUILD=ios"); @@ -58,10 +59,10 @@ int main(int argc, char *argv[]) { NSString *tmp_path = [NSString stringWithFormat:@"TMP=%@/tmp", resourcePath, nil]; putenv((char *)[tmp_path UTF8String]); #endif - + NSLog(@"Initializing python"); Py_Initialize(); - + #if PY_MAJOR_VERSION == 2 PySys_SetArgv(argc, argv); #else @@ -143,9 +144,16 @@ void export_orientation() { void load_custom_builtin_importer() { static const char *custom_builtin_importer = \ - "import sys, imp\n" \ + "import sys, imp, types\n" \ "from os import environ\n" \ "from os.path import exists, join\n" \ + "try:\n" \ + " # python 3\n" + " import _imp\n" \ + " EXTS = _imp.extension_suffixes()\n" \ + " sys.modules['subprocess'] = types.ModuleType(name='subprocess')\n" \ + "except ImportError:\n" \ + " EXTS = ['.so']\n" "# Fake redirection to supress console output\n" \ "if environ.get('KIVY_NO_CONSOLE', '0') == '1':\n" \ " class fakestd(object):\n" \ @@ -156,29 +164,32 @@ void load_custom_builtin_importer() { "# Custom builtin importer for precompiled modules\n" \ "class CustomBuiltinImporter(object):\n" \ " def find_module(self, fullname, mpath=None):\n" \ + " # print(f'find_module() fullname={fullname} mpath={mpath}')\n" \ " if '.' not in fullname:\n" \ " return\n" \ " if not mpath:\n" \ " return\n" \ " part = fullname.rsplit('.')[-1]\n" \ - " fn = join(mpath[0], '{}.so'.format(part))\n" \ - " if exists(fn):\n" \ - " return self\n" \ + " for ext in EXTS:\n" \ + " fn = join(list(mpath)[0], '{}{}'.format(part, ext))\n" \ + " # print('find_module() {}'.format(fn))\n" \ + " if exists(fn):\n" \ + " return self\n" \ " return\n" \ " def load_module(self, fullname):\n" \ " f = fullname.replace('.', '_')\n" \ " mod = sys.modules.get(f)\n" \ " if mod is None:\n" \ - " # print 'LOAD DYNAMIC', f, sys.modules.keys()\n" \ + " # print('LOAD DYNAMIC', f, sys.modules.keys())\n" \ " try:\n" \ " mod = imp.load_dynamic(f, f)\n" \ " except ImportError:\n" \ - " # import traceback; traceback.print_exc();\n" \ - " # print 'LOAD DYNAMIC FALLBACK', fullname\n" \ + " import traceback; traceback.print_exc();\n" \ + " # print('LOAD DYNAMIC FALLBACK', fullname)\n" \ " mod = imp.load_dynamic(fullname, fullname)\n" \ " sys.modules[fullname] = mod\n" \ " return mod\n" \ " return mod\n" \ - "sys.meta_path.append(CustomBuiltinImporter())"; + "sys.meta_path.insert(0, CustomBuiltinImporter())"; PyRun_SimpleString(custom_builtin_importer); } diff --git a/tests/test_python3/main.py b/tests/test_python3/main.py index 98440b8..9697d54 100644 --- a/tests/test_python3/main.py +++ b/tests/test_python3/main.py @@ -1 +1,54 @@ print("Python 3 running!") +import sys +print(f"sys.path: {sys.path}") +import os +import traceback + +modules_to_tests = [ + "math", "_sre", "array", + "binascii", "multiprocessing", + "subprocess" +] + +for name in modules_to_tests: + print(f"- import {name}: ", end="") + try: + __import__(name) + print("OK") + except ImportError: + print("FAIL") + traceback.print_exc() + +# test pyobjus +print("- import pyobjus start") +import pyobjus +print("- import done") +from pyobjus import autoclass +NSNotificationCenter = autoclass("NSNotificationCenter") + +# test ios +import ios + +from kivy.app import App +from kivy.lang import Builder + +class TestApp(App): + def build(self): + return Builder.load_string(""" +RelativeLayout: + GridLayout: + cols: 2 + + Button: + text: "Hello Python 3!" + font_size: dp(48) + + TextInput: + font_size: dp(24) + + Widget + Widget + +""") + +TestApp().run() diff --git a/toolchain.py b/toolchain.py index 922f85f..6804164 100755 --- a/toolchain.py +++ b/toolchain.py @@ -148,6 +148,8 @@ class Arch(object): self.ctx.include_dir, d.format(arch=self)) for d in self.ctx.include_dirs] + include_dirs += ["-I{}".format( + join(self.ctx.dist_dir, "include", self.arch))] env = {} ccache = sh.which('ccache') @@ -427,6 +429,7 @@ class Recipe(object): "libraries": [], "include_dir": None, "include_per_arch": False, + "include_name": None, "frameworks": [], "sources": [], "pbx_frameworks": [], @@ -621,10 +624,11 @@ class Recipe(object): self.ctx = ctx include_dir = None if self.include_dir: + include_name = self.include_name or self.name if self.include_per_arch: - include_dir = join("{arch.arch}", self.name) + include_dir = join("{arch.arch}", include_name) else: - include_dir = join("common", self.name) + include_dir = join("common", include_name) if include_dir: print("Include dir added: {}".format(include_dir)) self.ctx.include_dirs.append(include_dir) @@ -880,7 +884,8 @@ class Recipe(object): arch_dir = "common" if self.include_per_arch: arch_dir = arch.arch - dest_dir = join(self.ctx.include_dir, arch_dir, self.name) + include_name = self.include_name or self.name + dest_dir = join(self.ctx.include_dir, arch_dir, include_name) if exists(dest_dir): shutil.rmtree(dest_dir) build_dir = self.get_build_dir(arch.arch) From 9ad9abf9b605f15793223b700db0eb65c57a9b24 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Fri, 9 Nov 2018 18:48:08 +0100 Subject: [PATCH 31/42] fix cookiecutter project for python3 --- .gitignore | 1 + recipes/python3/xcompile.patch | 8 +-- toolchain.py | 12 ++++ .../main.m | 68 +++++++++++++++---- .../project.pbxproj | 18 +++-- 5 files changed, 84 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index 229be10..445896d 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ src/ios/iosbuild/ src/ios/ios.c *.DS_Store* *-ios/ +__pycache__ diff --git a/recipes/python3/xcompile.patch b/recipes/python3/xcompile.patch index f3c2ec9..f5e0e9f 100644 --- a/recipes/python3/xcompile.patch +++ b/recipes/python3/xcompile.patch @@ -106,10 +106,10 @@ fi ;; hp*|HP*) DYNLOADFILE="dynload_hpux.o";; -+ # Disable dynamic loading on iOS -+ iOS/*) DYNLOADFILE="dynload_stub.o";; -+ tvOS/*) DYNLOADFILE="dynload_stub.o";; -+ watchOS/*) DYNLOADFILE="dynload_stub.o";; ++ # Dynamic loading on iOS ++ iOS/*) DYNLOADFILE="dynload_shlib.o";; ++ tvOS/*) DYNLOADFILE="dynload_shlib.o";; ++ watchOS/*) DYNLOADFILE="dynload_shlib.o";; *) # use dynload_shlib.c and dlopen() if we have it; otherwise stub # out any dynamic loading diff --git a/toolchain.py b/toolchain.py index 6804164..08e8b52 100755 --- a/toolchain.py +++ b/toolchain.py @@ -1096,6 +1096,15 @@ def ensure_dir(filename): makedirs(filename) +def ensure_recipes_loaded(ctx): + for recipe in Recipe.list_recipes(): + key = "{}.build_all".format(recipe) + if key not in ctx.state: + continue + recipe = Recipe.get_recipe(recipe, ctx) + recipe.init_with_ctx(ctx) + + def update_pbxproj(filename): # list all the compiled recipes ctx = Context() @@ -1318,6 +1327,7 @@ Xcode: from cookiecutter.main import cookiecutter ctx = Context() + ensure_recipes_loaded(ctx) template_dir = join(curdir, "tools", "templates") context = { "title": args.name, @@ -1327,6 +1337,8 @@ Xcode: "project_dir": realpath(args.directory), "version": "1.0.0", "dist_dir": ctx.dist_dir, + "python_version": ctx.python_ver, + "python_major": ctx.python_major } cookiecutter(template_dir, no_input=True, extra_context=context) filename = join( diff --git a/tools/templates/{{ cookiecutter.project_name }}-ios/main.m b/tools/templates/{{ cookiecutter.project_name }}-ios/main.m index ba91039..10ba0d3 100644 --- a/tools/templates/{{ cookiecutter.project_name }}-ios/main.m +++ b/tools/templates/{{ cookiecutter.project_name }}-ios/main.m @@ -5,7 +5,11 @@ #import #import -#include "{{ cookiecutter.kivy_dir }}/dist/root/python/include/python2.7/Python.h" +{%- if cookiecutter.python_major == 2 %} +#include "{{ cookiecutter.kivy_dir }}/dist/root/python2/include/python2.7/Python.h" +{%- else %} +#include "{{ cookiecutter.kivy_dir }}/dist/root/python3/include/python3.7m/Python.h" +{%- endif %} #include "{{ cookiecutter.kivy_dir }}/dist/include/common/sdl2/SDL_main.h" #include @@ -22,11 +26,12 @@ int main(int argc, char *argv[]) { // Special environment to prefer .pyo, and don't write bytecode if .py are found // because the process will not have a write attribute on the device. - putenv("PYTHONOPTIMIZE=2"); putenv("PYTHONDONTWRITEBYTECODE=1"); putenv("PYTHONNOUSERSITE=1"); putenv("PYTHONPATH=."); - //putenv("PYTHONVERBOSE=1"); + putenv("PYTHONUNBUFFERED=1"); + // putenv("PYTHONVERBOSE=1"); + // putenv("PYOBJUS_DEBUG=1"); // Kivy environment to prefer some implementation on iOS platform putenv("KIVY_BUILD=ios"); @@ -44,12 +49,31 @@ int main(int argc, char *argv[]) { export_orientation(); NSString * resourcePath = [[NSBundle mainBundle] resourcePath]; +#if PY_MAJOR_VERSION == 2 NSLog(@"PythonHome is: %s", (char *)[resourcePath UTF8String]); Py_SetPythonHome((char *)[resourcePath UTF8String]); +#else + NSString *python_home = [NSString stringWithFormat:@"PYTHONHOME=%@", resourcePath, nil]; + putenv((char *)[python_home UTF8String]); + + NSString *python_path = [NSString stringWithFormat:@"PYTHONPATH=%@:%@/lib/python3.7/:%@/lib/python3.7/site-packages", resourcePath, resourcePath, resourcePath, nil]; + putenv((char *)[python_path UTF8String]); + + NSString *tmp_path = [NSString stringWithFormat:@"TMP=%@/tmp", resourcePath, nil]; + putenv((char *)[tmp_path UTF8String]); +#endif NSLog(@"Initializing python"); Py_Initialize(); + +#if PY_MAJOR_VERSION == 2 PySys_SetArgv(argc, argv); +#else + wchar_t** python_argv = PyMem_RawMalloc(sizeof(wchar_t *) *argc); + for (int i = 0; i < argc; i++) + python_argv[i] = Py_DecodeLocale(argv[i], NULL); + PySys_SetArgv(argc, python_argv); +#endif // If other modules are using the thread, we need to initialize them before. PyEval_InitThreads(); @@ -58,14 +82,20 @@ int main(int argc, char *argv[]) { load_custom_builtin_importer(); // Search and start main.py +#if PY_MAJOR_VERSION == 2 +#define MAIN_EXT @"pyo" +#else +#define MAIN_EXT @"pyc" +#endif + const char * prog = [ - [[NSBundle mainBundle] pathForResource:@"YourApp/main" ofType:@"pyo"] cStringUsingEncoding: + [[NSBundle mainBundle] pathForResource:@"YourApp/main" ofType:MAIN_EXT] cStringUsingEncoding: NSUTF8StringEncoding]; - NSLog(@"Running main.pyo: %s", prog); + NSLog(@"Running main.py: %s", prog); FILE* fd = fopen(prog, "r"); if ( fd == NULL ) { ret = 1; - NSLog(@"Unable to open main.pyo, abort."); + NSLog(@"Unable to open main.py, abort."); } else { ret = PyRun_SimpleFileEx(fd, prog, 1); if (ret != 0) @@ -117,9 +147,16 @@ void export_orientation() { void load_custom_builtin_importer() { static const char *custom_builtin_importer = \ - "import sys, imp\n" \ + "import sys, imp, types\n" \ "from os import environ\n" \ "from os.path import exists, join\n" \ + "try:\n" \ + " # python 3\n" + " import _imp\n" \ + " EXTS = _imp.extension_suffixes()\n" \ + " sys.modules['subprocess'] = types.ModuleType(name='subprocess')\n" \ + "except ImportError:\n" \ + " EXTS = ['.so']\n" "# Fake redirection to supress console output\n" \ "if environ.get('KIVY_NO_CONSOLE', '0') == '1':\n" \ " class fakestd(object):\n" \ @@ -130,29 +167,32 @@ void load_custom_builtin_importer() { "# Custom builtin importer for precompiled modules\n" \ "class CustomBuiltinImporter(object):\n" \ " def find_module(self, fullname, mpath=None):\n" \ + " # print(f'find_module() fullname={fullname} mpath={mpath}')\n" \ " if '.' not in fullname:\n" \ " return\n" \ " if not mpath:\n" \ " return\n" \ " part = fullname.rsplit('.')[-1]\n" \ - " fn = join(mpath[0], '{}.so'.format(part))\n" \ - " if exists(fn):\n" \ - " return self\n" \ + " for ext in EXTS:\n" \ + " fn = join(list(mpath)[0], '{}{}'.format(part, ext))\n" \ + " # print('find_module() {}'.format(fn))\n" \ + " if exists(fn):\n" \ + " return self\n" \ " return\n" \ " def load_module(self, fullname):\n" \ " f = fullname.replace('.', '_')\n" \ " mod = sys.modules.get(f)\n" \ " if mod is None:\n" \ - " # print 'LOAD DYNAMIC', f, sys.modules.keys()\n" \ + " # print('LOAD DYNAMIC', f, sys.modules.keys())\n" \ " try:\n" \ " mod = imp.load_dynamic(f, f)\n" \ " except ImportError:\n" \ - " # import traceback; traceback.print_exc();\n" \ - " # print 'LOAD DYNAMIC FALLBACK', fullname\n" \ + " import traceback; traceback.print_exc();\n" \ + " # print('LOAD DYNAMIC FALLBACK', fullname)\n" \ " mod = imp.load_dynamic(fullname, fullname)\n" \ " sys.modules[fullname] = mod\n" \ " return mod\n" \ " return mod\n" \ - "sys.meta_path.append(CustomBuiltinImporter())"; + "sys.meta_path.insert(0, CustomBuiltinImporter())"; PyRun_SimpleString(custom_builtin_importer); } diff --git a/tools/templates/{{ cookiecutter.project_name }}-ios/{{ cookiecutter.project_name }}.xcodeproj/project.pbxproj b/tools/templates/{{ cookiecutter.project_name }}-ios/{{ cookiecutter.project_name }}.xcodeproj/project.pbxproj index cb58807..94571f6 100755 --- a/tools/templates/{{ cookiecutter.project_name }}-ios/{{ cookiecutter.project_name }}.xcodeproj/project.pbxproj +++ b/tools/templates/{{ cookiecutter.project_name }}-ios/{{ cookiecutter.project_name }}.xcodeproj/project.pbxproj @@ -33,7 +33,7 @@ 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 2CB5F34517D5233A006187AB /* bridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bridge.h; sourceTree = SOURCE_ROOT; }; 2CB5F34617D5233A006187AB /* bridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = bridge.m; sourceTree = SOURCE_ROOT; }; - 59738AB41A8BB5D8001B2C0C /* lib */ = {isa = PBXFileReference; lastKnownFileType = folder; name = lib; path = {{ cookiecutter.dist_dir }}/root/python/lib; sourceTree = ""; }; + 59738AB41A8BB5D8001B2C0C /* lib */ = {isa = PBXFileReference; lastKnownFileType = folder; name = lib; path = {{ cookiecutter.dist_dir }}/root/python{{ cookiecutter.python_major }}/lib; sourceTree = ""; }; 59738AB61A8BB71F001B2C0C /* include */ = {isa = PBXFileReference; lastKnownFileType = folder; name = include; path = {{ cookiecutter.dist_dir }}/hostpython/include; sourceTree = ""; }; 59738ABA1A8E19AA001B2C0C /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = {{ cookiecutter.project_name }}/Images.xcassets; sourceTree = ""; }; 59738AD01A8E62D6001B2C0C /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default-568h@2x.png"; path = "LaunchImages/Default-568h@2x.png"; sourceTree = ""; }; @@ -234,7 +234,11 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/bash; - shellScript = "{{ cookiecutter.dist_dir }}/hostpython/bin/python -OO -m compileall \"$PROJECT_DIR\"/YourApp"; + {%- if cookiecutter.python_major == 2 %} + shellScript = "{{ cookiecutter.dist_dir }}/hostpython2/bin/python -OO -m compileall \"$PROJECT_DIR\"/YourApp"; + {%- else %} + shellScript = "{{ cookiecutter.dist_dir }}/hostpython3/bin/python -m compileall -f -b \"$PROJECT_DIR\"/YourApp"; + {%- endif %} }; /* End PBXShellScriptBuildPhase section */ @@ -250,7 +254,11 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/bash; - shellScript = "find \"$PROJECT_DIR\"/YourApp/ -iname '*.py' -exec rm {} \\; -or -iname '*.pyc' -exec rm {} \\;"; + {%- if cookiecutter.python_major == 2 %} + shellScript = "find \"$PROJECT_DIR\"/YourApp/ -regex '.*\\.py[c]*' -delete"; + {%- else %} + shellScript = "find \"$PROJECT_DIR\"/YourApp/ -regex '.*\\.py' -delete"; + {%- endif %} }; /* End PBXShellScriptBuildPhase section */ @@ -343,8 +351,8 @@ isa = XCBuildConfiguration; buildSettings = { DEAD_CODE_STRIPPING = NO; + ENABLE_BITCODE = NO; USER_HEADER_SEARCH_PATHS = {{ cookiecutter.dist_dir }}/root/include/; - VALID_ARCHS = x86_64; }; name = Debug; }; @@ -352,9 +360,9 @@ isa = XCBuildConfiguration; buildSettings = { DEAD_CODE_STRIPPING = NO; + ENABLE_BITCODE = NO; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; USER_HEADER_SEARCH_PATHS = {{ cookiecutter.dist_dir }}/root/include/; - VALID_ARCHS = x86_64; }; name = Release; }; From 0e52dab46872a2b7f3992ca4a3e65294759a331d Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Fri, 9 Nov 2018 19:14:05 +0100 Subject: [PATCH 32/42] fix recipes order with hostpython/python alias that didnt work in the first run --- recipes/hostpython.py | 12 +++++++++--- recipes/python.py | 12 +++++++++--- toolchain.py | 1 + 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/recipes/hostpython.py b/recipes/hostpython.py index 3291cc3..f5c6cd1 100644 --- a/recipes/hostpython.py +++ b/recipes/hostpython.py @@ -7,9 +7,15 @@ class HostpythonAliasRecipe(Recipe): def init_after_import(self, ctx): hostpython = ctx.state.get("hostpython") if not hostpython: - print("WARNING: no hostpython set yet, so you need to specify") - print("WARNING: either hostpython2 or hostpython3 in your deps") - else: + # search in wanted_recipes if it's the first time + if "hostpython2" in ctx.wanted_recipes: + hostpython = "hostpython2" + elif "hostpython3" in ctx.wanted_recipes: + hostpython = "hostpython3" + else: + print("WARNING: no hostpython set yet, so you need to specify") + print("WARNING: either hostpython2 or hostpython3 in your deps") + if python: self.depends = [hostpython] recipe = HostpythonAliasRecipe() diff --git a/recipes/python.py b/recipes/python.py index 359f03f..d6e713f 100644 --- a/recipes/python.py +++ b/recipes/python.py @@ -7,9 +7,15 @@ class PythonAliasRecipe(Recipe): def init_after_import(self, ctx): python = ctx.state.get("python") if not python: - print("WARNING: no python set yet, so you need to specify") - print("WARNING: either python2 or python3 in your deps") - else: + # search in wanted_recipes if it's the first time + if "python2" in ctx.wanted_recipes: + python = "python2" + elif "python3" in ctx.wanted_recipes: + python = "python3" + else: + print("WARNING: no python set yet, so you need to specify") + print("WARNING: either python2 or python3 in your deps") + if python: self.depends = [python] recipe = PythonAliasRecipe() diff --git a/toolchain.py b/toolchain.py index 6804164..484438b 100755 --- a/toolchain.py +++ b/toolchain.py @@ -1051,6 +1051,7 @@ def build_recipes(names, ctx): # gather all the dependencies print("Want to build {}".format(names)) graph = Graph() + ctx.wanted_recipes = names[:] recipe_to_load = names recipe_loaded = [] while names: From 7f139e382e2c5576bfdbe9c19ebc749c9022759a Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Fri, 9 Nov 2018 20:39:18 +0100 Subject: [PATCH 33/42] remove pymoodstocks recipes, the service got shutdown --- recipes/pymoodstocks/__init__.py | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 recipes/pymoodstocks/__init__.py diff --git a/recipes/pymoodstocks/__init__.py b/recipes/pymoodstocks/__init__.py deleted file mode 100644 index a4eb0be..0000000 --- a/recipes/pymoodstocks/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -from toolchain import PythonRecipe - - -class PyMoodstocksRecipe(PythonRecipe): - version = "master" - url = "https://github.com/tito/pymoodstocks/archive/{version}.zip" - depends = ["moodstocks", "kivy", "pyobjus"] - sources = ["src/ios"] - archs = ["i386"] - - -recipe = PyMoodstocksRecipe() - - From 7412603d0be511ed17fb5012c2b890b0b9accb73 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Fri, 9 Nov 2018 20:43:00 +0100 Subject: [PATCH 34/42] update readme --- README.rst | 62 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 15 deletions(-) diff --git a/README.rst b/README.rst index f0f32cb..42306b2 100644 --- a/README.rst +++ b/README.rst @@ -12,6 +12,9 @@ The toolchain supports: - iPhone Simulator (x86_64) - iPhone / iOS (armv7 and arm64) +You can select between Python 2.7 or Python 3.7 by specifying the recipes +`python2` or `python3` when building. + These recipes are not ported to the new toolchain yet: - lxml @@ -39,10 +42,10 @@ Currently, the toolchain requires a few tools for compilation. You will need: brew install autoconf automake libtool pkg-config brew link libtool -#. Install Cython (0.26.1):: +#. Install Cython (0.28.1):: # pip method if available (sudo might be needed.) - pip install cython==0.26.1 + pip install cython==0.28.1 Using the toolchain @@ -56,26 +59,50 @@ contained in a `recipe`. You can list the available recipes and their versions with:: $ ./toolchain.py recipes + audiostream master + click master + cymunk master + distribute 0.7.3 + ffmpeg 2.6.3 + ffpyplayer v3.2 + flask master freetype 2.5.5 - hostpython 2.7.1 + hostlibffi 3.2.1 + hostpython2 2.7.1 + hostpython3 3.7.1 ios master - kivy ios-poly-arch + itsdangerous master + jinja2 master + kivy 1.10.1 libffi 3.2.1 - openssl 1.0.2e + libjpeg v9a + libpng 1.6.26 + markupsafe master + moodstocks 4.1.5 + numpy 1.9.1 + openssl 1.0.2k + photolibrary master + pil 2.8.2 + plyer master + pycrypto 2.6.1 + pykka 1.2.1 pyobjus master - python 2.7.1 - sdl2 iOS-improvements + python2 2.7.1 + python3 3.7.1 + pyyaml 3.11 + sdl2 2.0.8 sdl2_image 2.0.0 sdl2_mixer 2.0.0 sdl2_ttf 2.0.12 + werkzeug master Then, start the compilation with:: - $ ./toolchain.py build kivy + $ ./toolchain.py build python3 kivy You can build recipes at the same time by adding them as parameters:: - $ ./toolchain.py build openssl kivy + $ ./toolchain.py build python3 openssl kivy Recipe builds can be removed via the clean command e.g.:: @@ -87,7 +114,7 @@ You can think of it as follows: the kivy recipe will compile everything necessary for a minimal working version of Kivy. Don't grab a coffee, just do diner. Compiling all the libraries for the first -time, 4x over (remember, 4 archs, 2 per platforms by default) will take time. +time, 3x over (remember, 3 archs, x86_64, armv7, arm64) will take time. For a complete list of available commands, type:: @@ -155,7 +182,7 @@ Reducing the application size If you would like to reduce the size of your distributed app, there are a few things you can do to achieve this: -#. Minimize the `build/python/lib/python27.zip`: this contains all the python +#. Minimize the `build/pythonX/lib/pythonXX.zip`: this contains all the python modules. You can edit the zip file and remove all the files you'll not use (reduce encodings, remove xml, email...) @@ -164,18 +191,18 @@ things you can do to achieve this: Python dynamic modules and will remove needed symbols. #. By default, the iOS package compiles binaries for all processor - architectures, namely x86, x86_64, armv7 and arm64 as per the guidelines from + architectures, namely x86_64, armv7 and arm64 as per the guidelines from Apple. You can reduce the size of your ipa significantly by removing the - x86 and x86_64 architectures as they are usually used only for the emulator. + x86_64 architecture as they are used only for the emulator. The procedure is to first compile/build all the host recipes as is:: - ./toolchain.py build hostpython + ./toolchain.py build hostpython3 Then build all the rest of the recipes using --arch=armv7 --arch=arm64 arguments as follows:: - ./toolchain.py build kivy --arch=armv7 --arch=arm64 + ./toolchain.py build python3 kivy --arch=armv7 --arch=arm64 Note that these packages will not run in the iOS emulators, so use them only for deployment. @@ -213,6 +240,11 @@ Fatal error: "stdio.h" file not found You must build with bitcode disabled (Xcode setting ENABLE_BITCODE should be No). We don't support bitcode. You need to go to the project setting, and disable bitcode. +You don't have permissions to run + It is due to invalid archs, search for them and check it. Maybe you + targetted a simulator but have only armv7/arm64. Maybe you want to target + your iPad but it as only x86_64. + Support ------- From 61b5c86b914397cf02ea4cf096e6590f86c950e6 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Fri, 9 Nov 2018 23:53:36 +0100 Subject: [PATCH 35/42] use tempfile for managing CC/CXX, and it also prevent leaking file every compilation --- toolchain.py | 69 ++++++++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/toolchain.py b/toolchain.py index d81f60e..c039d69 100755 --- a/toolchain.py +++ b/toolchain.py @@ -17,6 +17,7 @@ import io import json import shutil import fnmatch +import tempfile from datetime import datetime try: from urllib.request import FancyURLopener, urlcleanup @@ -152,7 +153,6 @@ class Arch(object): join(self.ctx.dist_dir, "include", self.arch))] env = {} - ccache = sh.which('ccache') cc = sh.xcrun("-find", "-sdk", self.sdk, "clang").strip() cxx = sh.xcrun("-find", "-sdk", self.sdk, "clang++").strip() @@ -166,40 +166,45 @@ class Arch(object): ]) cc += " " + flags cxx += " " + flags + + use_ccache = environ.get("USE_CCACHE", "1") + ccache = None + if use_ccache == "1": + ccache = sh.which('ccache') if ccache: ccache = ccache.strip() - use_ccache = environ.get("USE_CCACHE", "1") - if use_ccache != '1': - env["CC"] = cc - env["CXX"] = cxx - else: - if not self._ccsh: - self._ccsh = ccsh = sh.mktemp().strip() - with open(ccsh, 'w') as f: - f.write('#!/bin/sh\n') - f.write(ccache + ' ' + cc + ' "$@"\n') - sh.chmod('+x', ccsh) - self._cxxsh = cxxsh = sh.mktemp().strip() - with open(cxxsh, 'w') as f: - f.write('#!/bin/sh\n') - f.write(ccache + ' ' + cxx + ' "$@"\n') - sh.chmod('+x', cxxsh) - else: - ccsh = self._ccsh - cxxsh = self._cxxsh - env["USE_CCACHE"] = '1' - env["CCACHE"] = ccache - env["CC"] = ccsh - env["CXX"] = cxxsh + env["USE_CCACHE"] = "1" + env["CCACHE"] = ccache + env.update({k: v for k, v in environ.items() if k.startswith('CCACHE_')}) + env.setdefault('CCACHE_MAXSIZE', '10G') + env.setdefault('CCACHE_HARDLINK', 'true') + env.setdefault('CCACHE_SLOPPINESS', ('file_macro,time_macros,' + 'include_file_mtime,include_file_ctime,file_stat_matches')) - env.update({k: v for k, v in environ.items() if k.startswith('CCACHE_')}) - env.setdefault('CCACHE_MAXSIZE', '10G') - env.setdefault('CCACHE_HARDLINK', 'true') - env.setdefault('CCACHE_SLOPPINESS', ('file_macro,time_macros,' - 'include_file_mtime,include_file_ctime,file_stat_matches')) - else: - env["CC"] = cc - env["CXX"] = cxx + if not self._ccsh: + self._ccsh = tempfile.NamedTemporaryFile() + self._cxxsh = tempfile.NamedTemporaryFile() + sh.chmod("+x", self._ccsh.name) + sh.chmod("+x", self._cxxsh.name) + self._ccsh.write(b'#!/bin/sh\n') + self._cxxsh.write(b'#!/bin/sh\n') + if ccache: + print("CC and CXX will use ccache") + self._ccsh.write( + (ccache + ' ' + cc + ' "$@"\n').encode("utf8")) + self._cxxsh.write( + (ccache + ' ' + cxx + ' "$@"\n').encode("utf8")) + else: + print("CC and CXX will not use ccache") + self._ccsh.write( + (cc + ' "$@"\n').encode("utf8")) + self._cxxsh.write( + (cxx + ' "$@"\n').encode("utf8")) + self._ccsh.flush() + self._cxxsh.flush() + + env["CC"] = self._ccsh.name + env["CXX"] = self._cxxsh.name env["AR"] = sh.xcrun("-find", "-sdk", self.sdk, "ar").strip() env["LD"] = sh.xcrun("-find", "-sdk", self.sdk, "ld").strip() env["OTHER_CFLAGS"] = " ".join(include_dirs) From fa5229f2a49eee9ba57c358d21fa07988d17fa11 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Sat, 10 Nov 2018 01:40:55 +0100 Subject: [PATCH 36/42] make python/hostpython version in the first list of recipes mandatory, otherwise we dont know which python version it will uses --- recipes/hostpython.py | 11 ++++++++--- recipes/python.py | 9 +++++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/recipes/hostpython.py b/recipes/hostpython.py index f5c6cd1..308ce28 100644 --- a/recipes/hostpython.py +++ b/recipes/hostpython.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +import sys from toolchain import Recipe class HostpythonAliasRecipe(Recipe): @@ -13,9 +14,13 @@ class HostpythonAliasRecipe(Recipe): elif "hostpython3" in ctx.wanted_recipes: hostpython = "hostpython3" else: - print("WARNING: no hostpython set yet, so you need to specify") - print("WARNING: either hostpython2 or hostpython3 in your deps") - if python: + print("") + print("ERROR: No hostpython version set in the build.") + print("ERROR: Add python2 or python3 in your recipes:") + print("ERROR: ./toolchain.py build python3 ...") + print("") + sys.exit(1) + if hostpython: self.depends = [hostpython] recipe = HostpythonAliasRecipe() diff --git a/recipes/python.py b/recipes/python.py index d6e713f..f7b0ae8 100644 --- a/recipes/python.py +++ b/recipes/python.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +import sys from toolchain import Recipe class PythonAliasRecipe(Recipe): @@ -13,8 +14,12 @@ class PythonAliasRecipe(Recipe): elif "python3" in ctx.wanted_recipes: python = "python3" else: - print("WARNING: no python set yet, so you need to specify") - print("WARNING: either python2 or python3 in your deps") + print("") + print("ERROR: No Python version set in the build.") + print("ERROR: Add python2 or python3 in your recipes:") + print("ERROR: ./toolchain.py build python3 ...") + print("") + sys.exit(1) if python: self.depends = [python] From 4258cfd64b70a9dcdc30d8d1203435634864dba7 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Sat, 10 Nov 2018 10:09:27 +0100 Subject: [PATCH 37/42] remove moodstocks, service is gone --- recipes/moodstocks/__init__.py | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 recipes/moodstocks/__init__.py diff --git a/recipes/moodstocks/__init__.py b/recipes/moodstocks/__init__.py deleted file mode 100644 index d572c37..0000000 --- a/recipes/moodstocks/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -from toolchain import Recipe - - -class MoodstocksRecipe(Recipe): - version = "4.1.5" - url = "https://moodstocks.com/static/releases/moodstocks-ios-sdk-{version}.zip" - frameworks = ["Moodstocks.framework"] - archs = ["i386"] - pbx_frameworks = [ - "Moodstocks", "AVFoundation", "CoreMedia", "CoreVideo", "CFNetwork"] - - -recipe = MoodstocksRecipe() - - From c9ca2de91240344c18fbc41aafa667225a017c69 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Sat, 10 Nov 2018 10:14:39 +0100 Subject: [PATCH 38/42] fixes plyer and pkgresources recipes that was depending on old platform --- recipes/pkgresources/__init__.py | 9 ++++----- recipes/plyer/__init__.py | 6 ++---- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/recipes/pkgresources/__init__.py b/recipes/pkgresources/__init__.py index a46869f..97eb325 100644 --- a/recipes/pkgresources/__init__.py +++ b/recipes/pkgresources/__init__.py @@ -1,17 +1,16 @@ from toolchain import Recipe, shprint from os.path import join import sh -import os class pkg_resources(Recipe): depends = ["hostpython", "python"] - archs = ['i386'] + archs = ["x86_64"] url = "" def prebuild_arch(self, arch): - sh.cp("pkg_resources.py", join(self.ctx.dist_dir, "root", "python", "lib", "python2.7", "site-packages", "pkg_resources.py")) + sh.cp("pkg_resources.py", + join(self.ctx.site_packages_dir, "pkg_resources.py")) + recipe = pkg_resources() - - diff --git a/recipes/plyer/__init__.py b/recipes/plyer/__init__.py index 17ae7f0..4a9ab99 100644 --- a/recipes/plyer/__init__.py +++ b/recipes/plyer/__init__.py @@ -1,12 +1,10 @@ -# pure-python package, this can be removed when we'll support any python package from toolchain import PythonRecipe - class PlyerRecipe(PythonRecipe): version = "master" url = "https://github.com/kivy/plyer/archive/{version}.zip" depends = ["python", "pyobjus"] - archs = ["i386"] + archs = ["x86_64"] + recipe = PlyerRecipe() - From 6f295fd23f0b8ba36f1185ed035c4d27a88fa83a Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Fri, 16 Nov 2018 10:35:50 +0100 Subject: [PATCH 39/42] xcode: remove old include that is not needed anymore --- .../{{ cookiecutter.project_name }}.xcodeproj/project.pbxproj | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tools/templates/{{ cookiecutter.project_name }}-ios/{{ cookiecutter.project_name }}.xcodeproj/project.pbxproj b/tools/templates/{{ cookiecutter.project_name }}-ios/{{ cookiecutter.project_name }}.xcodeproj/project.pbxproj index 94571f6..937a3f9 100755 --- a/tools/templates/{{ cookiecutter.project_name }}-ios/{{ cookiecutter.project_name }}.xcodeproj/project.pbxproj +++ b/tools/templates/{{ cookiecutter.project_name }}-ios/{{ cookiecutter.project_name }}.xcodeproj/project.pbxproj @@ -11,7 +11,6 @@ 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; }; 2CB5F34717D5233A006187AB /* bridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CB5F34617D5233A006187AB /* bridge.m */; }; 59738AB51A8BB5D8001B2C0C /* lib in Resources */ = {isa = PBXBuildFile; fileRef = 59738AB41A8BB5D8001B2C0C /* lib */; }; - 59738AB71A8BB71F001B2C0C /* include in Resources */ = {isa = PBXBuildFile; fileRef = 59738AB61A8BB71F001B2C0C /* include */; }; 59738ABB1A8E19AA001B2C0C /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 59738ABA1A8E19AA001B2C0C /* Images.xcassets */; }; 59738ADB1A8E62D6001B2C0C /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 59738AD01A8E62D6001B2C0C /* Default-568h@2x.png */; }; 59738ADC1A8E62D6001B2C0C /* Default-667h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 59738AD11A8E62D6001B2C0C /* Default-667h@2x.png */; }; @@ -34,7 +33,6 @@ 2CB5F34517D5233A006187AB /* bridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bridge.h; sourceTree = SOURCE_ROOT; }; 2CB5F34617D5233A006187AB /* bridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = bridge.m; sourceTree = SOURCE_ROOT; }; 59738AB41A8BB5D8001B2C0C /* lib */ = {isa = PBXFileReference; lastKnownFileType = folder; name = lib; path = {{ cookiecutter.dist_dir }}/root/python{{ cookiecutter.python_major }}/lib; sourceTree = ""; }; - 59738AB61A8BB71F001B2C0C /* include */ = {isa = PBXFileReference; lastKnownFileType = folder; name = include; path = {{ cookiecutter.dist_dir }}/hostpython/include; sourceTree = ""; }; 59738ABA1A8E19AA001B2C0C /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = {{ cookiecutter.project_name }}/Images.xcassets; sourceTree = ""; }; 59738AD01A8E62D6001B2C0C /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default-568h@2x.png"; path = "LaunchImages/Default-568h@2x.png"; sourceTree = ""; }; 59738AD11A8E62D6001B2C0C /* Default-667h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default-667h@2x.png"; path = "LaunchImages/Default-667h@2x.png"; sourceTree = ""; }; @@ -104,7 +102,6 @@ isa = PBXGroup; children = ( 59738ABA1A8E19AA001B2C0C /* Images.xcassets */, - 59738AB61A8BB71F001B2C0C /* include */, 59738AB41A8BB5D8001B2C0C /* lib */, 01532DA9137C099F0076F6BF /* icon.png */, 8D1107310486CEB800E47090 /* {{ cookiecutter.project_name }}-Info.plist */, @@ -198,7 +195,6 @@ 59738ADB1A8E62D6001B2C0C /* Default-568h@2x.png in Resources */, 59738ADD1A8E62D6001B2C0C /* Default-763h@3x.png in Resources */, 59738AE21A8E62D6001B2C0C /* Default-Portrait@3x~ipad.png in Resources */, - 59738AB71A8BB71F001B2C0C /* include in Resources */, 59738AE51A8E62D6001B2C0C /* Default@3x.png in Resources */, 59738ADF1A8E62D6001B2C0C /* Default-Landscape@2x.png in Resources */, ); From cfc9dc1c29124d343ce1c164a498e72be6126a3d Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Fri, 16 Nov 2018 10:42:12 +0100 Subject: [PATCH 40/42] libffi/hostlibffi: force the binary to be python2.7, as by default osx don't have an alias for python2. This will allow the build system to use system python2.7 if brew python2 is not installed. Closes #309 --- recipes/hostlibffi/__init__.py | 3 ++- recipes/libffi/__init__.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/recipes/hostlibffi/__init__.py b/recipes/hostlibffi/__init__.py index 6f8e08e..a9cfda8 100644 --- a/recipes/hostlibffi/__init__.py +++ b/recipes/hostlibffi/__init__.py @@ -42,7 +42,8 @@ class LibffiRecipe(Recipe): "generate-darwin-source-and-headers.py", "_generate-darwin-source-and-headers.py") shprint(sh.touch, "generate-darwin-source-and-headers.py") - shprint(sh.python2, "_generate-darwin-source-and-headers.py", "--only-osx") + python27 = sh.Command("python2.7") + shprint(python27, "_generate-darwin-source-and-headers.py", "--only-osx") shprint(sh.xcodebuild, self.ctx.concurrent_xcodebuild, "ONLY_ACTIVE_ARCH=NO", diff --git a/recipes/libffi/__init__.py b/recipes/libffi/__init__.py index a9f3cac..98c64e1 100644 --- a/recipes/libffi/__init__.py +++ b/recipes/libffi/__init__.py @@ -31,7 +31,8 @@ class LibffiRecipe(Recipe): "generate-darwin-source-and-headers.py", "_generate-darwin-source-and-headers.py") shprint(sh.touch, "generate-darwin-source-and-headers.py") - shprint(sh.python2, "_generate-darwin-source-and-headers.py", "--only-ios") + python27 = sh.Command("python2.7") + shprint(python27, "_generate-darwin-source-and-headers.py", "--only-ios") shprint(sh.xcodebuild, self.ctx.concurrent_xcodebuild, "ONLY_ACTIVE_ARCH=NO", "ARCHS={}".format(arch.arch), From 7b5e28d643e6c9998632a587863ba7af5dec95f7 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Fri, 16 Nov 2018 10:52:02 +0100 Subject: [PATCH 41/42] add an error message for creating a project without python2 or python3 compiled. Closes #311 --- toolchain.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/toolchain.py b/toolchain.py index c039d69..198013b 100755 --- a/toolchain.py +++ b/toolchain.py @@ -1334,6 +1334,13 @@ Xcode: from cookiecutter.main import cookiecutter ctx = Context() ensure_recipes_loaded(ctx) + + if not hasattr(ctx, "python_ver"): + print("ERROR: No python recipes compiled!") + print("ERROR: You must have compiled at least python2 or") + print("ERROR: python3 recipes to be able to create a project.") + sys.exit(1) + template_dir = join(curdir, "tools", "templates") context = { "title": args.name, From 679fc62256ffb87b6101840563fc2952d7166e1b Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Fri, 16 Nov 2018 15:24:19 +0100 Subject: [PATCH 42/42] cookiecutter: fix tests for python2 --- tools/templates/{{ cookiecutter.project_name }}-ios/main.m | 2 +- .../{{ cookiecutter.project_name }}.xcodeproj/project.pbxproj | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/templates/{{ cookiecutter.project_name }}-ios/main.m b/tools/templates/{{ cookiecutter.project_name }}-ios/main.m index 10ba0d3..f237b7b 100644 --- a/tools/templates/{{ cookiecutter.project_name }}-ios/main.m +++ b/tools/templates/{{ cookiecutter.project_name }}-ios/main.m @@ -5,7 +5,7 @@ #import #import -{%- if cookiecutter.python_major == 2 %} +{%- if cookiecutter.python_major == "2" %} #include "{{ cookiecutter.kivy_dir }}/dist/root/python2/include/python2.7/Python.h" {%- else %} #include "{{ cookiecutter.kivy_dir }}/dist/root/python3/include/python3.7m/Python.h" diff --git a/tools/templates/{{ cookiecutter.project_name }}-ios/{{ cookiecutter.project_name }}.xcodeproj/project.pbxproj b/tools/templates/{{ cookiecutter.project_name }}-ios/{{ cookiecutter.project_name }}.xcodeproj/project.pbxproj index 937a3f9..21068e4 100755 --- a/tools/templates/{{ cookiecutter.project_name }}-ios/{{ cookiecutter.project_name }}.xcodeproj/project.pbxproj +++ b/tools/templates/{{ cookiecutter.project_name }}-ios/{{ cookiecutter.project_name }}.xcodeproj/project.pbxproj @@ -230,7 +230,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/bash; - {%- if cookiecutter.python_major == 2 %} + {%- if cookiecutter.python_major == "2" %} shellScript = "{{ cookiecutter.dist_dir }}/hostpython2/bin/python -OO -m compileall \"$PROJECT_DIR\"/YourApp"; {%- else %} shellScript = "{{ cookiecutter.dist_dir }}/hostpython3/bin/python -m compileall -f -b \"$PROJECT_DIR\"/YourApp"; @@ -250,7 +250,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/bash; - {%- if cookiecutter.python_major == 2 %} + {%- if cookiecutter.python_major == "2" %} shellScript = "find \"$PROJECT_DIR\"/YourApp/ -regex '.*\\.py[c]*' -delete"; {%- else %} shellScript = "find \"$PROJECT_DIR\"/YourApp/ -regex '.*\\.py' -delete";