add / update recipes and build changes for Python 3.6.6 compatibility (#315)
* add / update recipes and build changes for Python 3.6.6 compatibility * include Python 3 apt packages in travis build script * use Python 3.6 in Travis * Enable _blake2 and _sha3 in Python 3. Remove unnecessary files. * change zope.interface version * update cffi version
This commit is contained in:
parent
f12460e83a
commit
e08f6ee73c
80 changed files with 2063 additions and 3644 deletions
p4a/pythonforandroid
|
@ -1,11 +1,11 @@
|
|||
from os.path import join, dirname, isdir, exists, isfile, split, realpath, basename
|
||||
from os.path import basename, dirname, exists, isdir, isfile, join, realpath
|
||||
import importlib
|
||||
import zipfile
|
||||
import glob
|
||||
from shutil import rmtree
|
||||
from six import PY2, with_metaclass
|
||||
|
||||
import hashlib
|
||||
from re import match
|
||||
|
||||
import sh
|
||||
import shutil
|
||||
|
@ -20,7 +20,6 @@ from pythonforandroid.logger import (logger, info, warning, error, debug, shprin
|
|||
from pythonforandroid.util import (urlretrieve, current_directory, ensure_dir)
|
||||
|
||||
# this import is necessary to keep imp.load_source from complaining :)
|
||||
import pythonforandroid.recipes
|
||||
|
||||
|
||||
if PY2:
|
||||
|
@ -149,7 +148,7 @@ class Recipe(with_metaclass(RecipeMeta)):
|
|||
|
||||
urlretrieve(url, target, report_hook)
|
||||
return target
|
||||
elif parsed_url.scheme in ('git', 'git+ssh', 'git+http', 'git+https'):
|
||||
elif parsed_url.scheme in ('git', 'git+file', 'git+ssh', 'git+http', 'git+https'):
|
||||
if isdir(target):
|
||||
with current_directory(target):
|
||||
shprint(sh.git, 'fetch', '--tags')
|
||||
|
@ -168,43 +167,6 @@ class Recipe(with_metaclass(RecipeMeta)):
|
|||
shprint(sh.git, 'submodule', 'update', '--recursive')
|
||||
return target
|
||||
|
||||
def extract_source(self, source, cwd):
|
||||
"""
|
||||
(internal) Extract the `source` into the directory `cwd`.
|
||||
"""
|
||||
if not source:
|
||||
return
|
||||
if isfile(source):
|
||||
info("Extract {} into {}".format(source, cwd))
|
||||
|
||||
if source.endswith(".tgz") or source.endswith(".tar.gz"):
|
||||
shprint(sh.tar, "-C", cwd, "-xvzf", source)
|
||||
|
||||
elif source.endswith(".tbz2") or source.endswith(".tar.bz2"):
|
||||
shprint(sh.tar, "-C", cwd, "-xvjf", source)
|
||||
|
||||
elif source.endswith(".zip"):
|
||||
zf = zipfile.ZipFile(source)
|
||||
zf.extractall(path=cwd)
|
||||
zf.close()
|
||||
|
||||
else:
|
||||
warning(
|
||||
"Error: cannot extract, unrecognized extension for {}"
|
||||
.format(source))
|
||||
raise Exception()
|
||||
|
||||
elif isdir(source):
|
||||
info("Copying {} into {}".format(source, cwd))
|
||||
|
||||
shprint(sh.cp, '-a', source, cwd)
|
||||
|
||||
else:
|
||||
warning(
|
||||
"Error: cannot extract or copy, unrecognized path {}"
|
||||
.format(source))
|
||||
raise Exception()
|
||||
|
||||
# def get_archive_rootdir(self, filename):
|
||||
# if filename.endswith(".tgz") or filename.endswith(".tar.gz") or \
|
||||
# filename.endswith(".tbz2") or filename.endswith(".tar.bz2"):
|
||||
|
@ -225,19 +187,19 @@ class Recipe(with_metaclass(RecipeMeta)):
|
|||
build directory.
|
||||
"""
|
||||
info("Applying patch {}".format(filename))
|
||||
filename = join(self.recipe_dir, filename)
|
||||
filename = join(self.get_recipe_dir(), filename)
|
||||
shprint(sh.patch, "-t", "-d", self.get_build_dir(arch), "-p1",
|
||||
"-i", filename, _tail=10)
|
||||
|
||||
def copy_file(self, filename, dest):
|
||||
info("Copy {} to {}".format(filename, dest))
|
||||
filename = join(self.recipe_dir, filename)
|
||||
filename = join(self.get_recipe_dir(), filename)
|
||||
dest = join(self.build_dir, dest)
|
||||
shutil.copy(filename, dest)
|
||||
|
||||
def append_file(self, filename, dest):
|
||||
info("Append {} to {}".format(filename, dest))
|
||||
filename = join(self.recipe_dir, filename)
|
||||
filename = join(self.get_recipe_dir(), filename)
|
||||
dest = join(self.build_dir, dest)
|
||||
with open(filename, "rb") as fd:
|
||||
data = fd.read()
|
||||
|
@ -329,7 +291,14 @@ class Recipe(with_metaclass(RecipeMeta)):
|
|||
return join(self.get_build_container_dir(arch), self.name)
|
||||
|
||||
def get_recipe_dir(self):
|
||||
# AND: Redundant, an equivalent property is already set by get_recipe
|
||||
"""
|
||||
Returns the local recipe directory or defaults to the core recipe
|
||||
directory.
|
||||
"""
|
||||
if self.ctx.local_recipes is not None:
|
||||
local_recipe_dir = join(self.ctx.local_recipes, self.name)
|
||||
if exists(local_recipe_dir):
|
||||
return local_recipe_dir
|
||||
return join(self.ctx.root_dir, 'recipes', self.name)
|
||||
|
||||
# Public Recipe API to be subclassed if needed
|
||||
|
@ -349,6 +318,16 @@ class Recipe(with_metaclass(RecipeMeta)):
|
|||
return
|
||||
|
||||
url = self.versioned_url
|
||||
ma = match(u'^(.+)#md5=([0-9a-f]{32})$', url)
|
||||
if ma: # fragmented URL?
|
||||
if self.md5sum:
|
||||
raise ValueError(
|
||||
('Received md5sum from both the {} recipe '
|
||||
'and its url').format(self.name))
|
||||
url = ma.group(1)
|
||||
expected_md5 = ma.group(2)
|
||||
else:
|
||||
expected_md5 = self.md5sum
|
||||
|
||||
shprint(sh.mkdir, '-p', join(self.ctx.packages_path, self.name))
|
||||
|
||||
|
@ -356,44 +335,41 @@ class Recipe(with_metaclass(RecipeMeta)):
|
|||
filename = shprint(sh.basename, url).stdout[:-1].decode('utf-8')
|
||||
|
||||
do_download = True
|
||||
|
||||
marker_filename = '.mark-{}'.format(filename)
|
||||
if exists(filename) and isfile(filename):
|
||||
if not exists(marker_filename):
|
||||
shprint(sh.rm, filename)
|
||||
elif self.md5sum:
|
||||
elif expected_md5:
|
||||
current_md5 = md5sum(filename)
|
||||
if current_md5 == self.md5sum:
|
||||
debug('Checked md5sum: downloaded expected content!')
|
||||
do_download = False
|
||||
else:
|
||||
info('Downloaded unexpected content...')
|
||||
if current_md5 != expected_md5:
|
||||
debug('* Generated md5sum: {}'.format(current_md5))
|
||||
debug('* Expected md5sum: {}'.format(self.md5sum))
|
||||
|
||||
debug('* Expected md5sum: {}'.format(expected_md5))
|
||||
raise ValueError(
|
||||
('Generated md5sum does not match expected md5sum '
|
||||
'for {} recipe').format(self.name))
|
||||
do_download = False
|
||||
else:
|
||||
do_download = False
|
||||
info('{} download already cached, skipping'
|
||||
.format(self.name))
|
||||
|
||||
# If we got this far, we will download
|
||||
if do_download:
|
||||
debug('Downloading {} from {}'.format(self.name, url))
|
||||
|
||||
shprint(sh.rm, '-f', marker_filename)
|
||||
self.download_file(url, filename)
|
||||
self.download_file(self.versioned_url, filename)
|
||||
shprint(sh.touch, marker_filename)
|
||||
|
||||
if exists(filename) and isfile(filename) and self.md5sum:
|
||||
if exists(filename) and isfile(filename) and expected_md5:
|
||||
current_md5 = md5sum(filename)
|
||||
if self.md5sum is not None:
|
||||
if current_md5 == self.md5sum:
|
||||
debug('Checked md5sum: downloaded expected content!')
|
||||
else:
|
||||
info('Downloaded unexpected content...')
|
||||
if expected_md5 is not None:
|
||||
if current_md5 != expected_md5:
|
||||
debug('* Generated md5sum: {}'.format(current_md5))
|
||||
debug('* Expected md5sum: {}'.format(self.md5sum))
|
||||
exit(1)
|
||||
debug('* Expected md5sum: {}'.format(expected_md5))
|
||||
raise ValueError(
|
||||
('Generated md5sum does not match expected md5sum '
|
||||
'for {} recipe').format(self.name))
|
||||
else:
|
||||
info('{} download already cached, skipping'.format(self.name))
|
||||
|
||||
def unpack(self, arch):
|
||||
info_main('Unpacking {} for {}'.format(self.name, arch))
|
||||
|
@ -404,8 +380,6 @@ class Recipe(with_metaclass(RecipeMeta)):
|
|||
if user_dir is not None:
|
||||
info('P4A_{}_DIR exists, symlinking instead'.format(
|
||||
self.name.lower()))
|
||||
# AND: Currently there's something wrong if I use ln, fix this
|
||||
warning('Using cp -a instead of symlink...fix this!')
|
||||
if exists(self.get_build_dir(arch)):
|
||||
return
|
||||
shprint(sh.rm, '-rf', build_dir)
|
||||
|
@ -421,11 +395,13 @@ class Recipe(with_metaclass(RecipeMeta)):
|
|||
|
||||
filename = shprint(
|
||||
sh.basename, self.versioned_url).stdout[:-1].decode('utf-8')
|
||||
ma = match(u'^(.+)#md5=([0-9a-f]{32})$', filename)
|
||||
if ma: # fragmented URL?
|
||||
filename = ma.group(1)
|
||||
|
||||
with current_directory(build_dir):
|
||||
directory_name = self.get_build_dir(arch)
|
||||
|
||||
# AND: Could use tito's get_archive_rootdir here
|
||||
if not exists(directory_name) or not isdir(directory_name):
|
||||
extraction_filename = join(
|
||||
self.ctx.packages_path, self.name, filename)
|
||||
|
@ -638,7 +614,6 @@ class Recipe(with_metaclass(RecipeMeta)):
|
|||
if len(logger.handlers) > 1:
|
||||
logger.removeHandler(logger.handlers[1])
|
||||
recipe = mod.recipe
|
||||
recipe.recipe_dir = dirname(recipe_file)
|
||||
recipe.ctx = ctx
|
||||
cls.recipes[name] = recipe
|
||||
return recipe
|
||||
|
@ -755,6 +730,10 @@ class PythonRecipe(Recipe):
|
|||
return join(
|
||||
Recipe.get_recipe('hostpython2', self.ctx).get_build_dir(),
|
||||
'hostpython')
|
||||
elif 'hostpython3crystax' in self.ctx.recipe_build_order:
|
||||
return join(
|
||||
Recipe.get_recipe('hostpython3crystax', self.ctx).get_build_dir(),
|
||||
'hostpython')
|
||||
else:
|
||||
python_recipe = self.ctx.python_recipe
|
||||
return 'python{}'.format(python_recipe.version)
|
||||
|
@ -779,6 +758,34 @@ class PythonRecipe(Recipe):
|
|||
env['PYTHONNOUSERSITE'] = '1'
|
||||
|
||||
if not self.call_hostpython_via_targetpython:
|
||||
# sets python headers/linkages...depending on python's recipe
|
||||
python_version = self.ctx.python_recipe.version
|
||||
python_short_version = '.'.join(python_version.split('.')[:2])
|
||||
if 'python2' in self.ctx.recipe_build_order:
|
||||
env['PYTHON_ROOT'] = self.ctx.get_python_install_dir()
|
||||
env['CFLAGS'] += ' -I' + env[
|
||||
'PYTHON_ROOT'] + '/include/python2.7'
|
||||
env['LDFLAGS'] += ' -L' + env['PYTHON_ROOT'] + '/lib' + \
|
||||
' -lpython2.7'
|
||||
elif self.ctx.python_recipe.from_crystax:
|
||||
ndk_dir_python = join(self.ctx.ndk_dir, 'sources',
|
||||
'python', python_version)
|
||||
env['CFLAGS'] += ' -I{} '.format(
|
||||
join(ndk_dir_python, 'include',
|
||||
'python'))
|
||||
env['LDFLAGS'] += ' -L{}'.format(
|
||||
join(ndk_dir_python, 'libs', arch.arch))
|
||||
env['LDFLAGS'] += ' -lpython{}m'.format(python_short_version)
|
||||
elif 'python3' in self.ctx.recipe_build_order:
|
||||
# This headers are unused cause python3 recipe was removed
|
||||
# TODO: should be reviewed when python3 recipe added
|
||||
env['PYTHON_ROOT'] = self.ctx.get_python_install_dir()
|
||||
env['CFLAGS'] += ' -I' + env[
|
||||
'PYTHON_ROOT'] + '/include/python{}m'.format(
|
||||
python_short_version)
|
||||
env['LDFLAGS'] += ' -L' + env['PYTHON_ROOT'] + '/lib' + \
|
||||
' -lpython{}m'.format(
|
||||
python_short_version)
|
||||
hppath = []
|
||||
hppath.append(join(dirname(self.hostpython_location), 'Lib'))
|
||||
hppath.append(join(hppath[0], 'site-packages'))
|
||||
|
@ -819,28 +826,12 @@ class PythonRecipe(Recipe):
|
|||
with current_directory(self.get_build_dir(arch.arch)):
|
||||
hostpython = sh.Command(self.hostpython_location)
|
||||
|
||||
|
||||
if self.ctx.python_recipe.from_crystax:
|
||||
# hppath = join(dirname(self.hostpython_location), 'Lib',
|
||||
# 'site-packages')
|
||||
hpenv = env.copy()
|
||||
# if 'PYTHONPATH' in hpenv:
|
||||
# hpenv['PYTHONPATH'] = ':'.join([hppath] +
|
||||
# hpenv['PYTHONPATH'].split(':'))
|
||||
# else:
|
||||
# hpenv['PYTHONPATH'] = hppath
|
||||
# hpenv['PYTHONHOME'] = self.ctx.get_python_install_dir()
|
||||
# shprint(hostpython, 'setup.py', 'build',
|
||||
# _env=hpenv, *self.setup_extra_args)
|
||||
shprint(hostpython, 'setup.py', 'install', '-O2',
|
||||
'--root={}'.format(self.ctx.get_python_install_dir()),
|
||||
'--install-lib=.',
|
||||
# AND: will need to unhardcode the 3.5 when adding 2.7 (and other crystax supported versions)
|
||||
_env=hpenv, *self.setup_extra_args)
|
||||
# site_packages_dir = self.ctx.get_site_packages_dir()
|
||||
# built_files = glob.glob(join('build', 'lib*', '*'))
|
||||
# for filen in built_files:
|
||||
# shprint(sh.cp, '-r', filen, join(site_packages_dir, split(filen)[-1]))
|
||||
elif self.call_hostpython_via_targetpython:
|
||||
shprint(hostpython, 'setup.py', 'install', '-O2', _env=env,
|
||||
*self.setup_extra_args)
|
||||
|
@ -857,7 +848,6 @@ class PythonRecipe(Recipe):
|
|||
'--root={}'.format(self.ctx.get_python_install_dir()),
|
||||
'--install-lib=lib/python2.7/site-packages',
|
||||
_env=hpenv, *self.setup_extra_args)
|
||||
# AND: Hardcoded python2.7 needs fixing
|
||||
|
||||
# If asked, also install in the hostpython build dir
|
||||
if self.install_in_hostpython:
|
||||
|
@ -917,6 +907,7 @@ class CompiledComponentsPythonRecipe(PythonRecipe):
|
|||
shprint(hostpython, 'setup.py', self.build_cmd, '-v', _env=env,
|
||||
*self.setup_extra_args)
|
||||
|
||||
|
||||
class CppCompiledComponentsPythonRecipe(CompiledComponentsPythonRecipe):
|
||||
""" Extensions that require the cxx-stl """
|
||||
call_hostpython_via_targetpython = False
|
||||
|
@ -926,39 +917,34 @@ class CppCompiledComponentsPythonRecipe(CompiledComponentsPythonRecipe):
|
|||
keys = dict(
|
||||
ctx=self.ctx,
|
||||
arch=arch,
|
||||
arch_noeabi=arch.arch.replace('eabi', ''),
|
||||
pyroot=self.ctx.get_python_install_dir()
|
||||
arch_noeabi=arch.arch.replace('eabi', '')
|
||||
)
|
||||
env['LDSHARED'] = env['CC'] + ' -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions'
|
||||
env['CFLAGS'] += " -I{pyroot}/include/python2.7 " \
|
||||
" -I{ctx.ndk_dir}/platforms/android-{ctx.android_min_api}/arch-{arch_noeabi}/usr/include" \
|
||||
env['CFLAGS'] += " -I{ctx.ndk_dir}/platforms/android-{ctx.android_api}/arch-{arch_noeabi}/usr/include" \
|
||||
" -I{ctx.ndk_dir}/sources/cxx-stl/gnu-libstdc++/{ctx.toolchain_version}/include" \
|
||||
" -I{ctx.ndk_dir}/sources/cxx-stl/gnu-libstdc++/{ctx.toolchain_version}/libs/{arch.arch}/include".format(**keys)
|
||||
env['CXXFLAGS'] = env['CFLAGS'] + ' -frtti -fexceptions'
|
||||
env['LDFLAGS'] += " -L{ctx.ndk_dir}/sources/cxx-stl/gnu-libstdc++/{ctx.toolchain_version}/libs/{arch.arch}" \
|
||||
" -lpython2.7" \
|
||||
" -lgnustl_shared".format(**keys)
|
||||
|
||||
|
||||
return env
|
||||
|
||||
def build_compiled_components(self,arch):
|
||||
def build_compiled_components(self, arch):
|
||||
super(CppCompiledComponentsPythonRecipe, self).build_compiled_components(arch)
|
||||
|
||||
# Copy libgnustl_shared.so
|
||||
with current_directory(self.get_build_dir(arch.arch)):
|
||||
sh.cp(
|
||||
"{ctx.ndk_dir}/sources/cxx-stl/gnu-libstdc++/{ctx.toolchain_version}/libs/{arch.arch}/libgnustl_shared.so".format(ctx=self.ctx,arch=arch),
|
||||
"{ctx.ndk_dir}/sources/cxx-stl/gnu-libstdc++/{ctx.toolchain_version}/libs/{arch.arch}/libgnustl_shared.so".format(ctx=self.ctx, arch=arch),
|
||||
self.ctx.get_libs_dir(arch.arch)
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
class CythonRecipe(PythonRecipe):
|
||||
pre_build_ext = False
|
||||
cythonize = True
|
||||
cython_args = []
|
||||
call_hostpython_via_targetpython = False
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(CythonRecipe, self).__init__(*args, **kwargs)
|
||||
|
@ -1082,21 +1068,6 @@ class CythonRecipe(PythonRecipe):
|
|||
env['LIBLINK_PATH'] = liblink_path
|
||||
ensure_dir(liblink_path)
|
||||
|
||||
if self.ctx.python_recipe.from_crystax:
|
||||
env['CFLAGS'] = '-I{} '.format(
|
||||
join(self.ctx.ndk_dir, 'sources', 'python',
|
||||
self.ctx.python_recipe.version, 'include',
|
||||
'python')) + env['CFLAGS']
|
||||
|
||||
# Temporarily hardcode the -lpython3.x as this does not
|
||||
# get applied automatically in some environments. This
|
||||
# will need generalising, along with the other hardcoded
|
||||
# py3.5 references, to support other python3 or crystax
|
||||
# python versions.
|
||||
python3_version = self.ctx.python_recipe.version
|
||||
python3_version = '.'.join(python3_version.split('.')[:2])
|
||||
env['LDFLAGS'] = env['LDFLAGS'] + ' -lpython{}m'.format(python3_version)
|
||||
|
||||
return env
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue