diff --git a/pythonforandroid/patching.py b/pythonforandroid/patching.py new file mode 100644 index 0000000000..823a5fc727 --- /dev/null +++ b/pythonforandroid/patching.py @@ -0,0 +1,65 @@ +from os import uname + + +def check_all(*callables): + def check(**kwargs): + return all(c(**kwargs) for c in callables) + return check + + +def check_any(*callables): + def check(**kwargs): + return any(c(**kwargs) for c in callables) + return check + + +def is_platform(platform): + def is_x(**kwargs): + return uname()[0] == platform + return is_x + +is_linux = is_platform('Linux') +is_darwin = is_platform('Darwin') + + +def is_arch(xarch): + def is_x(arch, **kwargs): + return arch.arch == xarch + return is_x + + +def is_api_gt(apiver): + def is_x(recipe, **kwargs): + return recipe.ctx.android_api > apiver + return is_x + + +def is_api_gte(apiver): + def is_x(recipe, **kwargs): + return recipe.ctx.android_api >= apiver + return is_x + + +def is_api_lt(apiver): + def is_x(recipe, **kwargs): + return recipe.ctx.android_api < apiver + return is_x + + +def is_api_lte(apiver): + def is_x(recipe, **kwargs): + return recipe.ctx.android_api <= apiver + return is_x + + +def is_api(apiver): + def is_x(recipe, **kwargs): + return recipe.ctx.android_api == apiver + return is_x + + +def will_build(recipe_name): + def will(recipe, **kwargs): + return recipe_name in recipe.ctx.recipe_build_order + return will + diff --git a/pythonforandroid/recipes/kivysdl2python3/__init__.py b/pythonforandroid/recipes/kivysdl2python3/__init__.py index 22a2493294..e50736658f 100644 --- a/pythonforandroid/recipes/kivysdl2python3/__init__.py +++ b/pythonforandroid/recipes/kivysdl2python3/__init__.py @@ -12,15 +12,7 @@ class KivySDL2Recipe(CythonRecipe): site_packages_name = 'kivy' depends = ['sdl2', 'python2', 'pyjniussdl2'] - - def prebuild_arch(self, arch): - super(KivySDL2Recipe, self).prebuild_arch(arch) - build_dir = self.get_build_dir(arch.arch) - if exists(join(build_dir, '.patched')): - print('kivysdl2 already patched, skipping') - return - self.apply_patch('android_sdl2_compat.patch') - shprint(sh.touch, join(build_dir, '.patched')) + patches = ['android_sdl2_compat.patch'] def get_recipe_env(self, arch): env = super(KivySDL2Recipe, self).get_recipe_env(arch) diff --git a/pythonforandroid/recipes/numpy/__init__.py b/pythonforandroid/recipes/numpy/__init__.py index 5c8ae5d0a9..28e4be1dd5 100644 --- a/pythonforandroid/recipes/numpy/__init__.py +++ b/pythonforandroid/recipes/numpy/__init__.py @@ -1,8 +1,5 @@ -from pythonforandroid.toolchain import CompiledComponentsPythonRecipe, shprint, current_directory, warning -from os.path import exists, join -import sh -import glob +from pythonforandroid.toolchain import CompiledComponentsPythonRecipe, warning class NumpyRecipe(CompiledComponentsPythonRecipe): @@ -13,23 +10,17 @@ class NumpyRecipe(CompiledComponentsPythonRecipe): depends = ['python2'] + patches = ['patches/fix-numpy.patch', + 'patches/prevent_libs_check.patch', + 'patches/ar.patch', + 'patches/lib.patch'] + def prebuild_arch(self, arch): super(NumpyRecipe, self).prebuild_arch(arch) - build_dir = self.get_build_dir(arch.arch) - if exists(join(build_dir, '.patched')): - print('numpy already patched, skipping') - return - - self.apply_patch('patches/fix-numpy.patch', arch.arch) - self.apply_patch('patches/prevent_libs_check.patch', arch.arch) - self.apply_patch('patches/ar.patch', arch.arch) - self.apply_patch('patches/lib.patch', arch.arch) # AND: Fix this warning! warning('Numpy is built assuming the archiver name is ' 'arm-linux-androideabi-ar, which may not always be true!') - shprint(sh.touch, join(build_dir, '.patched')) - recipe = NumpyRecipe() diff --git a/pythonforandroid/recipes/pycrypto/__init__.py b/pythonforandroid/recipes/pycrypto/__init__.py index 4d52f8dba2..ac78a7f449 100644 --- a/pythonforandroid/recipes/pycrypto/__init__.py +++ b/pythonforandroid/recipes/pycrypto/__init__.py @@ -6,9 +6,8 @@ info, shprint, ) -from os.path import exists, join, realpath +from os.path import join import sh -import glob class PyCryptoRecipe(CompiledComponentsPythonRecipe): @@ -16,16 +15,9 @@ class PyCryptoRecipe(CompiledComponentsPythonRecipe): url = 'https://pypi.python.org/packages/source/p/pycrypto/pycrypto-{version}.tar.gz' depends = ['openssl', 'python2'] - def prebuild_arch(self, arch): - super(PyCryptoRecipe, self).prebuild_arch(arch) - build_dir = self.get_build_dir(arch.arch) - if exists(join(build_dir, '.patched')): - print('pycrypto already patched, skipping') - return - self.apply_patch('add_length.patch', arch.arch) - shprint(sh.touch, join(build_dir, '.patched')) + patches = ['add_length.patch'] - def get_recipe_env(self, arch): + def get_recipe_env(self, arch=None): env = super(PyCryptoRecipe, self).get_recipe_env(arch) openssl_build_dir = Recipe.get_recipe('openssl', self.ctx).get_build_dir(arch.arch) env['CC'] = '%s -I%s' % (env['CC'], join(openssl_build_dir, 'include')) diff --git a/pythonforandroid/recipes/pygame/__init__.py b/pythonforandroid/recipes/pygame/__init__.py index 231563ef80..2e763f9a8d 100644 --- a/pythonforandroid/recipes/pygame/__init__.py +++ b/pythonforandroid/recipes/pygame/__init__.py @@ -12,7 +12,11 @@ class PygameRecipe(Recipe): depends = ['python2', 'sdl'] conflicts = ['sdl2'] - def get_recipe_env(self, arch): + patches = ['fix-surface-access.patch', + 'fix-array-surface.patch', + 'fix-sdl-spam-log.patch'] + + def get_recipe_env(self, arch=None): env = super(PygameRecipe, self).get_recipe_env(arch) env['LDFLAGS'] = env['LDFLAGS'] + ' -L{}'.format( self.ctx.get_libs_dir(arch.arch)) @@ -27,15 +31,10 @@ def get_recipe_env(self, arch): return env def prebuild_arch(self, arch): - if exists(join(self.get_build_container_dir(arch.arch), '.patched')): - info('Pygame already patched, skipping.') + if self.is_patched(arch): return shprint(sh.cp, join(self.get_recipe_dir(), 'Setup'), join(self.get_build_dir(arch.arch), 'Setup')) - self.apply_patch(join('patches', 'fix-surface-access.patch'), arch.arch) - self.apply_patch(join('patches', 'fix-array-surface.patch'), arch.arch) - self.apply_patch(join('patches', 'fix-sdl-spam-log.patch'), arch.arch) - shprint(sh.touch, join(self.get_build_container_dir(arch.arch), '.patched')) def build_arch(self, arch): # AND: I'm going to ignore any extra pythonrecipe or cythonrecipe behaviour for now diff --git a/pythonforandroid/recipes/pyjnius/__init__.py b/pythonforandroid/recipes/pyjnius/__init__.py index 7ef1709c51..da42dc3eb6 100644 --- a/pythonforandroid/recipes/pyjnius/__init__.py +++ b/pythonforandroid/recipes/pyjnius/__init__.py @@ -1,25 +1,18 @@ -from pythonforandroid.toolchain import CythonRecipe, shprint, ArchARM, current_directory, info +from pythonforandroid.toolchain import CythonRecipe, shprint, current_directory, info +from pythonforandroid.patching import will_build import sh -import glob -from os.path import join, exists +from os.path import join class PyjniusRecipe(CythonRecipe): - version = 'master' + version = 'master' url = 'https://github.com/kivy/pyjnius/archive/{version}.zip' name = 'pyjnius' depends = ['python2', ('sdl2', 'sdl'), 'six'] site_packages_name = 'jnius' - def prebuild_arch(self, arch): - super(PyjniusRecipe, self).prebuild_arch(arch) - if 'sdl2' in self.ctx.recipe_build_order: - build_dir = self.get_build_dir(arch.arch) - if exists(join(build_dir, '.patched')): - print('pyjniussdl2 already pathed, skipping') - return - self.apply_patch('sdl2_jnienv_getter.patch', arch.arch) - shprint(sh.touch, join(build_dir, '.patched')) + + patches = [('sdl2_jnienv_getter.patch', will_build('sdl2')] def postbuild_arch(self, arch): super(PyjniusRecipe, self).postbuild_arch(arch) diff --git a/pythonforandroid/recipes/python2/__init__.py b/pythonforandroid/recipes/python2/__init__.py index 4e49a4fa5a..c54a465368 100644 --- a/pythonforandroid/recipes/python2/__init__.py +++ b/pythonforandroid/recipes/python2/__init__.py @@ -1,8 +1,7 @@ -from pythonforandroid.toolchain import Recipe, shprint, get_directory, current_directory, ArchARM, info +from pythonforandroid.toolchain import Recipe, shprint, current_directory, info +from pythonforandroid.patching import is_linux, is_darwin, is_api_gt from os.path import exists, join, realpath -from os import uname -import glob import sh @@ -14,39 +13,25 @@ class Python2Recipe(Recipe): depends = ['hostpython2'] conflicts = ['python3'] opt_depends = ['openssl'] - - def prebuild_arch(self, arch): - build_dir = self.get_build_container_dir(arch.arch) - if exists(join(build_dir, '.patched')): - info('Python2 already patched, skipping.') - return - self.apply_patch(join('patches', 'Python-{}-xcompile.patch'.format(self.version)), - arch.arch) - self.apply_patch(join('patches', 'Python-{}-ctypes-disable-wchar.patch'.format(self.version)), - arch.arch) - self.apply_patch(join('patches', 'disable-modules.patch'), arch.arch) - self.apply_patch(join('patches', 'fix-locale.patch'), arch.arch) - self.apply_patch(join('patches', 'fix-gethostbyaddr.patch'), arch.arch) - self.apply_patch(join('patches', 'fix-setup-flags.patch'), arch.arch) - self.apply_patch(join('patches', 'fix-filesystemdefaultencoding.patch'), arch.arch) - self.apply_patch(join('patches', 'fix-termios.patch'), arch.arch) - self.apply_patch(join('patches', 'custom-loader.patch'), arch.arch) - self.apply_patch(join('patches', 'verbose-compilation.patch'), arch.arch) - self.apply_patch(join('patches', 'fix-remove-corefoundation.patch'), arch.arch) - self.apply_patch(join('patches', 'fix-dynamic-lookup.patch'), arch.arch) - self.apply_patch(join('patches', 'fix-dlfcn.patch'), arch.arch) - self.apply_patch(join('patches', 'parsetuple.patch'), arch.arch) - # self.apply_patch(join('patches', 'ctypes-find-library.patch'), arch.arch) - self.apply_patch(join('patches', 'ctypes-find-library-updated.patch'), arch.arch) - - if uname()[0] == 'Linux': - self.apply_patch(join('patches', 'fix-configure-darwin.patch'), arch.arch) - self.apply_patch(join('patches', 'fix-distutils-darwin.patch'), arch.arch) - - if self.ctx.android_api > 19: - self.apply_patch(join('patches', 'fix-ftime-removal.patch'), arch.arch) - - shprint(sh.touch, join(build_dir, '.patched')) + + patches = ['patches/Python-{version}-xcompile.patch', + 'patches/Python-{version}-ctypes-disable-wchar.patch', + 'patches/disable-modules.patch', + 'patches/fix-locale.patch', + 'patches/fix-gethostbyaddr.patch', + 'patches/fix-setup-flags.patch', + 'patches/fix-filesystemdefaultencoding.patch', + 'patches/fix-termios.patch', + 'patches/custom-loader.patch', + 'patches/verbose-compilation.patch', + 'patches/fix-remove-corefoundation.patch', + 'patches/fix-dynamic-lookup.patch', + 'patches/fix-dlfcn.patch', + 'patches/parsetuple.patch', + 'patches/ctypes-find-library-updated.patch', + ('patches/fix-configure-darwin.patch', is_linux), + ('patches/fix-distutils-darwin.patch', is_linux), + ('patches/fix-ftime-removal.patch', is_api_gt(19))] def build_arch(self, arch): @@ -151,7 +136,7 @@ def do_python_build(self, arch): 'INSTSONAME=libpython2.7.so', _env=env) - if uname()[0] == 'Darwin': + if is_darwin(): shprint(sh.cp, join(self.get_recipe_dir(), 'patches', '_scproxy.py'), join('python-install', 'Lib')) shprint(sh.cp, join(self.get_recipe_dir(), 'patches', '_scproxy.py'), diff --git a/pythonforandroid/recipes/sdl2/__init__.py b/pythonforandroid/recipes/sdl2/__init__.py index 9edec09842..71d8d31ede 100644 --- a/pythonforandroid/recipes/sdl2/__init__.py +++ b/pythonforandroid/recipes/sdl2/__init__.py @@ -12,14 +12,7 @@ class LibSDL2Recipe(NDKRecipe): depends = ['python2', 'sdl2_image', 'sdl2_mixer', 'sdl2_ttf'] conflicts = ['sdl', 'pygame', 'pygame_bootstrap_components'] - def prebuild_arch(self, arch): - super(LibSDL2Recipe, self).prebuild_arch(arch) - build_dir = self.get_build_dir(arch.arch) - if exists(join(build_dir, '.patched')): - info('SDL2 already patched, skipping') - return - self.apply_patch('add_nativeSetEnv.patch', arch.arch) - shprint(sh.touch, join(build_dir, '.patched')) + patches = ['add_nativeSetEnv.patch'] def build_arch(self, arch): env = self.get_recipe_env(arch) diff --git a/pythonforandroid/recipes/sdl2_image/__init__.py b/pythonforandroid/recipes/sdl2_image/__init__.py index 8265d4ec88..9c7afe15e4 100644 --- a/pythonforandroid/recipes/sdl2_image/__init__.py +++ b/pythonforandroid/recipes/sdl2_image/__init__.py @@ -1,21 +1,14 @@ -from pythonforandroid.toolchain import NDKRecipe, shprint, info -from os.path import exists, join -import sh +from pythonforandroid.toolchain import NDKRecipe +from pythonforandroid.patching import is_arch + class LibSDL2Image(NDKRecipe): version = '2.0.0' url = 'https://www.libsdl.org/projects/SDL_image/release/SDL2_image-{version}.tar.gz' dir_name = 'SDL2_image' - - def prebuild_arch(self, arch): - super(LibSDL2Image, self).prebuild_arch(arch) - build_dir = self.get_build_dir(arch.arch) - if exists(join(build_dir, '.patched')): - info('SDL2_image already patched, skipping') - return - self.apply_patch('disable_webp.patch', arch.arch) - if arch.arch == 'x86': - self.apply_patch('disable_jpg.patch', arch.arch) - shprint(sh.touch, join(build_dir, '.patched')) + + patches = ['disable_webp.patch', + ('disable_jpg.patch', is_arch('x86'))] + recipe = LibSDL2Image() diff --git a/pythonforandroid/recipes/sdl2_mixer/__init__.py b/pythonforandroid/recipes/sdl2_mixer/__init__.py index 8788330363..d963ab0550 100644 --- a/pythonforandroid/recipes/sdl2_mixer/__init__.py +++ b/pythonforandroid/recipes/sdl2_mixer/__init__.py @@ -1,21 +1,12 @@ -from pythonforandroid.toolchain import NDKRecipe, shprint, info -from os.path import exists, join -import sh +from pythonforandroid.toolchain import NDKRecipe + class LibSDL2Mixer(NDKRecipe): version = '2.0.0' url = 'https://www.libsdl.org/projects/SDL_mixer/release/SDL2_mixer-{version}.tar.gz' dir_name = 'SDL2_mixer' - def prebuild_arch(self, arch): - super(LibSDL2Mixer, self).prebuild_arch(arch) - build_dir = self.get_build_dir(arch.arch) + patches = ['disable_modplug_mikmod_smpeg.patch'] - if exists(join(build_dir, '.patched')): - info('SDL2_mixer already patched, skipping') - return - self.apply_patch('disable_modplug_mikmod_smpeg.patch', - arch.arch) - shprint(sh.touch, join(build_dir, '.patched')) recipe = LibSDL2Mixer() diff --git a/pythonforandroid/recipes/sdl2python3/__init__.py b/pythonforandroid/recipes/sdl2python3/__init__.py index 8c51684c9d..865937a072 100644 --- a/pythonforandroid/recipes/sdl2python3/__init__.py +++ b/pythonforandroid/recipes/sdl2python3/__init__.py @@ -1,9 +1,7 @@ -from pythonforandroid.toolchain import NDKRecipe, shprint, current_directory, info_main -from os.path import exists, join +from pythonforandroid.toolchain import NDKRecipe, shprint, current_directory import sh - class LibSDL2Recipe(NDKRecipe): version = "2.0.3" url = "https://www.libsdl.org/release/SDL2-{version}.tar.gz" @@ -11,14 +9,7 @@ class LibSDL2Recipe(NDKRecipe): # depends = ['python2'] dir_name = 'SDL' - def prebuild_arch(self, arch): - super(LibSDL2Recipe, self).prebuild_arch(arch) - build_dir = self.get_build_dir(arch.arch) - if exists(join(build_dir, '.patched')): - print('SDL2 already patched, skipping') - return - self.apply_patch('add_nativeSetEnv.patch', arch.arch) - shprint(sh.touch, join(build_dir, '.patched')) + patches = ['add_nativeSetEnv.patch'] def build_arch(self, arch): env = self.get_recipe_env(arch) diff --git a/pythonforandroid/recipes/vispy/__init__.py b/pythonforandroid/recipes/vispy/__init__.py index 130a500009..b5aa0934cc 100644 --- a/pythonforandroid/recipes/vispy/__init__.py +++ b/pythonforandroid/recipes/vispy/__init__.py @@ -1,8 +1,5 @@ -from pythonforandroid.toolchain import PythonRecipe, shprint, current_directory -from os.path import exists, join -import sh -import glob +from pythonforandroid.toolchain import PythonRecipe class VispyRecipe(PythonRecipe): @@ -16,20 +13,12 @@ class VispyRecipe(PythonRecipe): depends = ['python2', 'numpy', 'pysdl2'] - def prebuild_arch(self, arch): - super(VispyRecipe, self).prebuild_arch(arch) - build_dir = self.get_build_dir(arch.arch) - if exists(join(build_dir, '.patched')): - print('vispy already patched, skipping') - return - self.apply_patch('disable_freetype.patch', arch.arch) - self.apply_patch('disable_font_triage.patch', arch.arch) - self.apply_patch('use_es2.patch', arch.arch) - self.apply_patch('remove_ati_check.patch', arch.arch) + patches = ['disable_freetype.patch', + 'disable_font_triage.patch', + 'use_es2.patch', + 'remove_ati_check.patch', + 'make_shader_es2_compliant.patch', + 'detect_finger_events.patch'] - self.apply_patch('make_shader_es2_compliant.patch', arch.arch) - self.apply_patch('detect_finger_events.patch', arch.arch) - - shprint(sh.touch, join(build_dir, '.patched')) recipe = VispyRecipe() diff --git a/pythonforandroid/toolchain.py b/pythonforandroid/toolchain.py index a99646f767..edd3ee70fe 100755 --- a/pythonforandroid/toolchain.py +++ b/pythonforandroid/toolchain.py @@ -1615,6 +1615,12 @@ class Recipe(object): '''A list of optional dependencies, that must be built before this recipe if they are built at all, but whose presence is not essential.''' + patches = [] + '''A list of patches to apply to the source. Values can be either a string + referring to the patch file relative to the recipe dir, or a tuple of the + string patch file and a callable, which will receive the kwargs `arch` and + `recipe`, which should return True if the patch should be applied.''' + archs = ['armeabi'] # Not currently implemented properly @property @@ -1981,6 +1987,32 @@ def prebuild_arch(self, arch): else: info('{} has no {}, skipping'.format(self.name, prebuild)) + def is_patched(self, arch): + build_dir = self.get_build_dir(arch.arch) + return exists(join(build_dir, '.patched')) + + def apply_patches(self, arch): + '''Apply any patches for the Recipe.''' + if self.patches: + info_main('Applying patches for {}[{}]' + .format(self.name, arch.arch)) + + if self.is_patched(arch): + info_main('{} already patched, skipping'.format(self.name)) + return + + for patch in self.patches: + if isinstance(patch, (tuple, list)): + patch, patch_check = patch + if not patch_check(arch=arch, recipe=self): + continue + + self.apply_patch( + patch.format(version=self.version, arch=arch.arch), + arch.arch) + + shprint(sh.touch, join(self.get_build_dir(arch.arch), '.patched')) + def should_build(self, arch): '''Should perform any necessary test and return True only if it needs building again. @@ -2309,6 +2341,7 @@ def build_recipes(build_order, python_modules, ctx): for recipe in recipes: info_main('Prebuilding {} for {}'.format(recipe.name, arch.arch)) recipe.prebuild_arch(arch) + recipe.apply_patches(arch) # 3) build packages info_main('# Building recipes')