|
2 | 2 | from pythonforandroid.toolchain import shprint, current_directory, info
|
3 | 3 | from pythonforandroid.patching import (is_darwin, is_api_gt,
|
4 | 4 | check_all, is_api_lt, is_ndk)
|
5 |
| -from pythonforandroid.logger import logger |
| 5 | +from pythonforandroid.logger import (logger, Err_Fore) |
6 | 6 | from pythonforandroid.util import ensure_dir
|
7 | 7 | from os.path import exists, join, realpath
|
8 | 8 | from os import environ
|
9 | 9 | import sh
|
10 | 10 |
|
11 | 11 |
|
| 12 | +# Here we set data for python's optional libraries, any optional future library |
| 13 | +# should be referenced into variable `libs_info` and maybe in `versioned_libs`. |
| 14 | +# Perhaps some additional operations had to be performed in functions: |
| 15 | +# - set_libs_flags: if the path for library/includes is in some location |
| 16 | +# defined dynamically by some function. |
| 17 | +# - do_python_build: if python has some specific argument to enable |
| 18 | +# external library support. |
| 19 | + |
| 20 | +# versioned_libs is a list with versioned libraries |
| 21 | +versioned_libs = ['openssl'] |
| 22 | + |
| 23 | +# libs_info is a dict where his keys are the optional recipes, |
| 24 | +# each value of libs_info is a dict: |
| 25 | +# - includes: list of includes (should be relative paths |
| 26 | +# which point to the includes). |
| 27 | +# - lib_links: list of ldflags needed to link python with the library. |
| 28 | +# - lib_path: relative path pointing to the library location, |
| 29 | +# (if is set to None, the library's build dir will be taken). |
| 30 | +libs_info = { |
| 31 | + 'openssl': { |
| 32 | + 'includes': ['include', join('include', 'openssl')], |
| 33 | + 'lib_links': ['-lcrypto', '-lssl'], |
| 34 | + 'lib_path': None, |
| 35 | + }, |
| 36 | + 'sqlite3': { |
| 37 | + 'includes': [''], |
| 38 | + 'lib_links': ['-lsqlite3'], |
| 39 | + 'lib_path': None, |
| 40 | + }, |
| 41 | + 'libffi': { |
| 42 | + 'includes': ['include'], |
| 43 | + 'lib_links': ['-lffi'], |
| 44 | + 'lib_path': '.libs', |
| 45 | + }, |
| 46 | + 'libexpat': { |
| 47 | + 'includes': ['lib'], |
| 48 | + 'lib_links': ['-lexpat'], |
| 49 | + 'lib_path': join('expat', 'lib', '.libs'), |
| 50 | + }, |
| 51 | +} |
| 52 | + |
| 53 | + |
12 | 54 | class Python3Recipe(TargetPythonRecipe):
|
13 | 55 | version = 'bpo-30386'
|
14 | 56 | url = 'https://github.com/inclement/cpython/archive/{version}.zip'
|
15 | 57 | name = 'python3'
|
16 | 58 |
|
17 | 59 | depends = ['hostpython3']
|
18 | 60 | conflicts = ['python3crystax', 'python2']
|
19 |
| - # opt_depends = ['openssl', 'sqlite3'] |
| 61 | + opt_depends = ['libffi', 'libexpat', 'openssl', 'sqlite3'] |
| 62 | + # TODO: More patches maybe be needed, but with those |
| 63 | + # two we successfully build and run a simple app |
| 64 | + patches = ['patches/python-3.x.x-libs.patch', |
| 65 | + 'patches/fix-termios.patch'] |
| 66 | + |
| 67 | + def set_libs_flags(self, env, arch=None): |
| 68 | + # Takes an env as argument and adds cflags/ldflags |
| 69 | + # based on libs_info and versioned_libs. |
| 70 | + env['OPENSSL_BUILD'] = '/path-to-openssl' |
| 71 | + env['SQLITE3_INC_DIR'] = '/path-to-sqlite3-includes' |
| 72 | + env['SQLITE3_LIB_DIR'] = '/path-to-sqlite3-library' |
| 73 | + |
| 74 | + for lib in self.opt_depends: |
| 75 | + if lib in self.ctx.recipe_build_order: |
| 76 | + logger.info( |
| 77 | + ''.join((Err_Fore.MAGENTA, '-> Activating flags for ', lib, |
| 78 | + Err_Fore.RESET))) |
| 79 | + r = Recipe.get_recipe(lib, self.ctx) |
| 80 | + b = r.get_build_dir(arch.arch) |
| 81 | + |
| 82 | + # Sets or modifies include/library base paths, |
| 83 | + # this should point to build directory, and some |
| 84 | + # libs has special build directories...so... |
| 85 | + # here we deal with it. |
| 86 | + inc_dir = b |
| 87 | + lib_dir = b |
| 88 | + if lib == 'sqlite3': |
| 89 | + lib_dir = r.get_lib_dir(arch) |
| 90 | + elif lib == 'libffi': |
| 91 | + inc_dir = join(inc_dir, r.get_host(arch)) |
| 92 | + lib_dir = join(lib_dir, r.get_host(arch)) |
| 93 | + elif lib == 'libexpat': |
| 94 | + inc_dir = join(b, 'expat') |
| 95 | + |
| 96 | + # It establishes the include's flags taking into |
| 97 | + # account the information provided in libs_info. |
| 98 | + if libs_info[lib]['includes']: |
| 99 | + includes = [ |
| 100 | + join(inc_dir, p) for p in libs_info[lib]['includes']] |
| 101 | + else: |
| 102 | + includes = [inc_dir] |
| 103 | + i_flags = ' -I' + ' -I'.join(includes) |
| 104 | + |
| 105 | + # It establishes the linking's flags taking into |
| 106 | + # account the information provided in libs_info. |
| 107 | + if libs_info[lib]['lib_path']: |
| 108 | + lib_dir = join(lib_dir, libs_info[lib]['lib_path']) |
| 109 | + if lib not in versioned_libs: |
| 110 | + l_flags = ' -L' + lib_dir + ' ' + ' '.join( |
| 111 | + libs_info[lib]['lib_links']) |
| 112 | + else: |
| 113 | + l_flags = ' -L' + lib_dir + ' ' + ' '.join( |
| 114 | + [i + r.version for i in libs_info[lib]['lib_links']]) |
| 115 | + |
| 116 | + # Inserts or appends to env. |
| 117 | + f = 'CPPFLAGS' |
| 118 | + env[f] = env[f] + i_flags if f in env else i_flags |
| 119 | + f = 'LDFLAGS' |
| 120 | + env[f] = env[f] + l_flags if f in env else l_flags |
| 121 | + |
| 122 | + # Sets special python compilation flags for some libs. |
| 123 | + # The openssl and sqlite env variables are set |
| 124 | + # via patch: patches/python-3.x.x-libs.patch |
| 125 | + if lib == 'openssl': |
| 126 | + env['OPENSSL_BUILD'] = b |
| 127 | + env['OPENSSL_VERSION'] = r.version |
| 128 | + elif lib == 'sqlite3': |
| 129 | + env['SQLITE3_INC_DIR'] = inc_dir |
| 130 | + env['SQLITE3_LIB_DIR'] = lib_dir |
| 131 | + elif lib == 'libffi': |
| 132 | + env['LIBFFI_CFLAGS'] = env['CFLAGS'] + i_flags |
| 133 | + env['LIBFFI_LIBS'] = l_flags |
| 134 | + return env |
20 | 135 |
|
21 | 136 | def build_arch(self, arch):
|
22 | 137 | recipe_build_dir = self.get_build_dir(arch.arch)
|
@@ -80,22 +195,36 @@ def build_arch(self, arch):
|
80 | 195 |
|
81 | 196 | env['SYSROOT'] = sysroot
|
82 | 197 |
|
| 198 | + # TODO: All the env variables should be moved |
| 199 | + # into method: get_recipe_env (all above included) |
| 200 | + env = self.set_libs_flags(env, arch) |
| 201 | + |
| 202 | + # Arguments for python configure |
| 203 | + # TODO: move ac_xx_ arguments to config.site |
| 204 | + configure_args = [ |
| 205 | + '--host={android_host}', |
| 206 | + '--build={android_build}', |
| 207 | + '--enable-shared', |
| 208 | + '--disable-ipv6', |
| 209 | + '--without-ensurepip', |
| 210 | + '--prefix={prefix}', |
| 211 | + '--exec-prefix={exec_prefix}', |
| 212 | + 'ac_cv_file__dev_ptmx=yes', |
| 213 | + 'ac_cv_file__dev_ptc=no', |
| 214 | + 'ac_cv_little_endian_double=yes' |
| 215 | + ] |
| 216 | + if 'libffi' in self.ctx.recipe_build_order: |
| 217 | + configure_args.append('--with-system-ffi') |
| 218 | + if 'libexpat' in self.ctx.recipe_build_order: |
| 219 | + configure_args.append('--with-system-expat') |
| 220 | + |
83 | 221 | if not exists('config.status'):
|
84 | 222 | shprint(sh.Command(join(recipe_build_dir, 'configure')),
|
85 |
| - *(' '.join(('--host={android_host}', |
86 |
| - '--build={android_build}', |
87 |
| - '--enable-shared', |
88 |
| - '--disable-ipv6', |
89 |
| - 'ac_cv_file__dev_ptmx=yes', |
90 |
| - 'ac_cv_file__dev_ptc=no', |
91 |
| - '--without-ensurepip', |
92 |
| - 'ac_cv_little_endian_double=yes', |
93 |
| - '--prefix={prefix}', |
94 |
| - '--exec-prefix={exec_prefix}')).format( |
95 |
| - android_host=android_host, |
96 |
| - android_build=android_build, |
97 |
| - prefix=sys_prefix, |
98 |
| - exec_prefix=sys_exec_prefix)).split(' '), _env=env) |
| 223 | + *(' '.join(configure_args).format( |
| 224 | + android_host=android_host, |
| 225 | + android_build=android_build, |
| 226 | + prefix=sys_prefix, |
| 227 | + exec_prefix=sys_exec_prefix)).split(' '), _env=env) |
99 | 228 |
|
100 | 229 | if not exists('python'):
|
101 | 230 | shprint(sh.make, 'all', _env=env)
|
|
0 commit comments