diff --git a/buildozer.spec.sample b/buildozer.spec.sample index a8a0da9c..7cba7bcf 100644 --- a/buildozer.spec.sample +++ b/buildozer.spec.sample @@ -92,7 +92,7 @@ android.permissions = INTERNET,READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE android.api = 23 # (int) Minimum API required -android.minapi = 16 +android.minapi = 21 # (int) Android SDK version to use android.sdk = 23 diff --git a/buildozer.spec.travis b/buildozer.spec.travis index a8a0da9c..7cba7bcf 100644 --- a/buildozer.spec.travis +++ b/buildozer.spec.travis @@ -92,7 +92,7 @@ android.permissions = INTERNET,READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE android.api = 23 # (int) Minimum API required -android.minapi = 16 +android.minapi = 21 # (int) Android SDK version to use android.sdk = 23 diff --git a/p4a/pythonforandroid/build.py b/p4a/pythonforandroid/build.py index ed406b09..461839c1 100644 --- a/p4a/pythonforandroid/build.py +++ b/p4a/pythonforandroid/build.py @@ -47,6 +47,8 @@ class Context(object): symlink_java_src = False # If True, will symlink instead of copying during build + java_build_tool = 'auto' + @property def packages_path(self): '''Where packages are downloaded before being unpacked''' @@ -158,7 +160,8 @@ class Context(object): self._ndk_dir = value def prepare_build_environment(self, user_sdk_dir, user_ndk_dir, - user_android_api, user_ndk_ver): + user_android_api, user_android_min_api, + user_ndk_ver): '''Checks that build dependencies exist and sets internal variables for the Android SDK etc. @@ -171,8 +174,6 @@ class Context(object): if self._build_env_prepared: return - # AND: This needs revamping to carefully check each dependency - # in turn ok = True # Work out where the Android SDK is @@ -184,7 +185,7 @@ class Context(object): if sdk_dir is None: # This seems used more conventionally sdk_dir = environ.get('ANDROID_HOME', None) if sdk_dir is None: # Checks in the buildozer SDK dir, useful - # # for debug tests of p4a + # for debug tests of p4a possible_dirs = glob.glob(expanduser(join( '~', '.buildozer', 'android', 'platform', 'android-sdk-*'))) possible_dirs = [d for d in possible_dirs if not @@ -226,6 +227,30 @@ class Context(object): error('You probably want to build with --arch=armeabi-v7a instead') exit(1) + # try to determinate min_api + android_min_api = None + if user_android_min_api: + android_min_api = user_android_min_api + if android_min_api is not None: + info('Getting Minimum Android API version from user argument') + if android_min_api is None: + android_min_api = environ.get("ANDROIDMINAPI", None) + if android_min_api is not None: + info('Found Android minimum api in $ANDROIDMINAPI') + if android_min_api is None: + info('Minimum Android API was not set, using current Android API ' + '{}'.format(android_api)) + android_min_api = android_api + android_min_api = int(android_min_api) + self.android_min_api = android_min_api + + info("Requested API {} (minimum {})".format( + self.android_api, self.android_min_api)) + + if self.android_min_api > android_api: + error('Android minimum api cannot be higher than Android api') + exit(1) + if exists(join(sdk_dir, 'tools', 'bin', 'avdmanager')): avdmanager = sh.Command(join(sdk_dir, 'tools', 'bin', 'avdmanager')) targets = avdmanager('list', 'target').stdout.decode('utf-8').split('\n') @@ -235,6 +260,7 @@ class Context(object): else: error('Could not find `android` or `sdkmanager` binaries in ' 'Android SDK. Exiting.') + exit(1) apis = [s for s in targets if re.match(r'^ *API level: ', s)] apis = [re.findall(r'[0-9]+', s) for s in apis] apis = [int(s[0]) for s in apis if s] @@ -323,8 +349,9 @@ class Context(object): warning('If the NDK dir result is correct, you don\'t ' 'need to manually set the NDK ver.') if ndk_ver is None: - warning('Android NDK version could not be found, exiting.') - exit(1) + warning('Android NDK version could not be found. This probably' + 'won\'t cause any problems, but if necessary you can' + 'set it with `--ndk-version=...`.') self.ndk_ver = ndk_ver info('Using {} NDK {}'.format(self.ndk.capitalize(), self.ndk_ver)) @@ -359,7 +386,7 @@ class Context(object): ok = False warning("Missing requirement: cython is not installed") - # AND: need to change if supporting multiple archs at once + # This would need to be changed if supporting multiarch APKs arch = self.archs[0] platform_dir = arch.platform_dir toolchain_prefix = arch.toolchain_prefix @@ -367,7 +394,7 @@ class Context(object): self.ndk_platform = join( self.ndk_dir, 'platforms', - 'android-{}'.format(self.android_api), + 'android-{}'.format(self.android_min_api), platform_dir) if not exists(self.ndk_platform): warning('ndk_platform doesn\'t exist: {}'.format( @@ -496,7 +523,7 @@ class Context(object): dir. ''' - # AND: This *must* be replaced with something more general in + # This needs to be replaced with something more general in # order to support multiple python versions and/or multiple # archs. if self.python_recipe.from_crystax: @@ -575,7 +602,6 @@ def build_recipes(build_order, python_modules, ctx): .format(recipe.name)) # 4) biglink everything - # AND: Should make this optional info_main('# Biglinking object files') if not ctx.python_recipe or not ctx.python_recipe.from_crystax: biglink(ctx, arch) @@ -666,12 +692,17 @@ def biglink(ctx, arch): info('target {}'.format(join(ctx.get_libs_dir(arch.arch), 'libpymodules.so'))) do_biglink = copylibs_function if ctx.copy_libs else biglink_function - do_biglink( - join(ctx.get_libs_dir(arch.arch), 'libpymodules.so'), - obj_dir.split(' '), - extra_link_dirs=[join(ctx.bootstrap.build_dir, - 'obj', 'local', arch.arch)], - env=env) + + # Move to the directory containing crtstart_so.o and crtend_so.o + # This is necessary with newer NDKs? A gcc bug? + with current_directory(join(ctx.ndk_platform, 'usr', 'lib')): + do_biglink( + join(ctx.get_libs_dir(arch.arch), 'libpymodules.so'), + obj_dir.split(' '), + extra_link_dirs=[join(ctx.bootstrap.build_dir, + 'obj', 'local', arch.arch), + os.path.abspath('.')], + env=env) def biglink_function(soname, objs_paths, extra_link_dirs=[], env=None): diff --git a/p4a/pythonforandroid/patching.py b/p4a/pythonforandroid/patching.py index 70d7e9c9..541bab85 100644 --- a/p4a/pythonforandroid/patching.py +++ b/p4a/pythonforandroid/patching.py @@ -30,31 +30,31 @@ def is_arch(xarch): def is_api_gt(apiver): def is_x(recipe, **kwargs): - return recipe.ctx.android_api > apiver + return recipe.ctx.android_min_api > apiver return is_x def is_api_gte(apiver): def is_x(recipe, **kwargs): - return recipe.ctx.android_api >= apiver + return recipe.ctx.android_min_api >= apiver return is_x def is_api_lt(apiver): def is_x(recipe, **kwargs): - return recipe.ctx.android_api < apiver + return recipe.ctx.android_min_api < apiver return is_x def is_api_lte(apiver): def is_x(recipe, **kwargs): - return recipe.ctx.android_api <= apiver + return recipe.ctx.android_min_api <= apiver return is_x def is_api(apiver): def is_x(recipe, **kwargs): - return recipe.ctx.android_api == apiver + return recipe.ctx.android_min_api == apiver return is_x @@ -68,4 +68,3 @@ def is_ndk(ndk): def is_x(recipe, **kwargs): return recipe.ctx.ndk == ndk return is_x - diff --git a/p4a/pythonforandroid/recipe.py b/p4a/pythonforandroid/recipe.py index 234a111a..d80d03bc 100644 --- a/p4a/pythonforandroid/recipe.py +++ b/p4a/pythonforandroid/recipe.py @@ -931,7 +931,7 @@ class CppCompiledComponentsPythonRecipe(CompiledComponentsPythonRecipe): ) 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_api}/arch-{arch_noeabi}/usr/include" \ + " -I{ctx.ndk_dir}/platforms/android-{ctx.android_min_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' diff --git a/p4a/pythonforandroid/toolchain.py b/p4a/pythonforandroid/toolchain.py index 028c540d..30ebd65d 100644 --- a/p4a/pythonforandroid/toolchain.py +++ b/p4a/pythonforandroid/toolchain.py @@ -141,6 +141,7 @@ def require_prebuilt_dist(func): ctx.prepare_build_environment(user_sdk_dir=self.sdk_dir, user_ndk_dir=self.ndk_dir, user_android_api=self.android_api, + user_android_min_api=self.android_min_api, user_ndk_ver=self.ndk_version) dist = self._dist if dist.needs_build: @@ -256,6 +257,9 @@ class ToolchainCL(object): generic_parser.add_argument( '--android-api', '--android_api', dest='android_api', default=0, type=int, help='The Android API level to build against.') + generic_parser.add_argument( + '--android-minapi', '--android_minapi', dest='android_min_api', default=0, type=int, + help='The Minimum Android API level to build against (will be used for all C compilation).') generic_parser.add_argument( '--ndk-version', '--ndk_version', dest='ndk_version', default='', help=('The version of the Android NDK. This is optional, ' @@ -499,6 +503,7 @@ class ToolchainCL(object): self.sdk_dir = args.sdk_dir self.ndk_dir = args.ndk_dir self.android_api = args.android_api + self.android_min_api = args.android_min_api self.ndk_version = args.ndk_version self.ctx.symlink_java_src = args.symlink_java_src self.ctx.java_build_tool = args.java_build_tool @@ -904,6 +909,7 @@ class ToolchainCL(object): ctx.prepare_build_environment(user_sdk_dir=self.sdk_dir, user_ndk_dir=self.ndk_dir, user_android_api=self.android_api, + user_android_min_api=self.android_min_api, user_ndk_ver=self.ndk_version) android = sh.Command(join(ctx.sdk_dir, 'tools', args.tool)) output = android( @@ -931,6 +937,7 @@ class ToolchainCL(object): ctx.prepare_build_environment(user_sdk_dir=self.sdk_dir, user_ndk_dir=self.ndk_dir, user_android_api=self.android_api, + user_android_min_api=self.android_min_api, user_ndk_ver=self.ndk_version) if platform in ('win32', 'cygwin'): adb = sh.Command(join(ctx.sdk_dir, 'platform-tools', 'adb.exe'))