Skip to content

Commit 61e6485

Browse files
committed
Rework of the arch environment to work with ndk r19+ (there is no way back)
Things done here: - Modifies target so we can use the toolchains `in-place` (as if we were using a standalone toolchain) - Removes some cflags that we don't need anymore - Move `macros` and `includes` from `CFLAGS` to `CPPFLAGS` (because this is the way it's supposed to be) - Move libraries from `LDFLAGS` to `LDLIBS` (again, the same as above) - Remove hardcoded cpu count in `MAKE` - Group environment variables and add some comments (to put some order and make easier for us to maintain it) - Remove `gcc` of environment (because it has been partially removed in ndk r18) Note: This will force us to use a minimal ndk version of 19 See also: https://developer.android.com/ndk/guides/other_build_systems
1 parent 6ca419e commit 61e6485

File tree

2 files changed

+65
-78
lines changed

2 files changed

+65
-78
lines changed

pythonforandroid/archs.py

Lines changed: 62 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from distutils.spawn import find_executable
22
from os import environ
3-
from os.path import (exists, join, dirname, split)
3+
from os.path import join, dirname, split
4+
from multiprocessing import cpu_count
45
from glob import glob
56

67
from pythonforandroid.recipe import Recipe
@@ -38,29 +39,34 @@ def include_dirs(self):
3839

3940
@property
4041
def target(self):
41-
target_data = self.command_prefix.split('-')
42-
return '-'.join(
43-
[target_data[0], 'none', target_data[1], target_data[2]])
42+
# As of NDK r19, the toolchains installed by default with the
43+
# NDK may be used in-place. The make_standalone_toolchain.py script
44+
# is no longer needed for interfacing with arbitrary build systems.
45+
# See: https://developer.android.com/ndk/guides/other_build_systems
46+
return '{triplet}{ndk_api}'.format(
47+
triplet=self.command_prefix, ndk_api=self.ctx.ndk_api)
4448

4549
def get_env(self, with_flags_in_cc=True, clang=False):
4650
env = {}
4751

52+
# CFLAGS and CXXFLAGS
4853
cflags = [
49-
'-DANDROID',
50-
'-fomit-frame-pointer',
51-
'-D__ANDROID_API__={}'.format(self.ctx.ndk_api)]
52-
if not clang:
53-
cflags.append('-mandroid')
54-
else:
55-
cflags.append('-target ' + self.target)
56-
toolchain = '{android_host}-{toolchain_version}'.format(
57-
android_host=self.ctx.toolchain_prefix,
58-
toolchain_version=self.ctx.toolchain_version)
59-
toolchain = join(self.ctx.ndk_dir, 'toolchains', toolchain,
60-
'prebuilt', build_platform)
61-
cflags.append('-gcc-toolchain {}'.format(toolchain))
62-
54+
'-target ' + self.target,
55+
'-fomit-frame-pointer']
6356
env['CFLAGS'] = ' '.join(cflags)
57+
env['CXXFLAGS'] = env['CFLAGS']
58+
59+
# CPPFLAGS (for macros and includes)
60+
cppflags = [
61+
'-DANDROID',
62+
'-D__ANDROID_API__={}'.format(self.ctx.ndk_api),
63+
'-I{}/sysroot/usr/include/{}'.format(
64+
self.ctx.ndk_dir, self.command_prefix),
65+
'-I' + join(self.ctx.get_python_install_dir(),
66+
'include/python{}'.format(
67+
self.ctx.python_recipe.version[0:3]))
68+
]
69+
env['CPPFLAGS'] = ' '.join(cppflags)
6470

6571
# Link the extra global link paths first before anything else
6672
# (such that overriding system libraries with them is possible)
@@ -69,39 +75,14 @@ def get_env(self, with_flags_in_cc=True, clang=False):
6975
for l in self.extra_global_link_paths
7076
]) + ' '
7177

72-
sysroot = join(self.ctx._ndk_dir, 'sysroot')
73-
if exists(sysroot):
74-
# post-15 NDK per
75-
# https://android.googlesource.com/platform/ndk/+/ndk-r15-release/docs/UnifiedHeaders.md
76-
env['CFLAGS'] += ' -isystem {}/sysroot/usr/include/{}'.format(
77-
self.ctx.ndk_dir, self.ctx.toolchain_prefix)
78-
env['CFLAGS'] += ' -I{}/sysroot/usr/include/{}'.format(
79-
self.ctx.ndk_dir, self.command_prefix)
80-
else:
81-
sysroot = self.ctx.ndk_platform
82-
env['CFLAGS'] += ' -I{}'.format(self.ctx.ndk_platform)
83-
env['CFLAGS'] += ' -isysroot {} '.format(sysroot)
84-
env['CFLAGS'] += '-I' + join(self.ctx.get_python_install_dir(),
85-
'include/python{}'.format(
86-
self.ctx.python_recipe.version[0:3])
87-
)
88-
89-
env['LDFLAGS'] += '--sysroot {} '.format(self.ctx.ndk_platform)
90-
91-
env["CXXFLAGS"] = env["CFLAGS"]
92-
93-
env["LDFLAGS"] += " ".join(['-lm', '-L' + self.ctx.get_libs_dir(self.arch)])
94-
95-
if self.ctx.ndk == 'crystax':
96-
env['LDFLAGS'] += ' -L{}/sources/crystax/libs/{} -lcrystax'.format(self.ctx.ndk_dir, self.arch)
97-
98-
toolchain_prefix = self.ctx.toolchain_prefix
99-
toolchain_version = self.ctx.toolchain_version
100-
command_prefix = self.command_prefix
101-
102-
env['TOOLCHAIN_PREFIX'] = toolchain_prefix
103-
env['TOOLCHAIN_VERSION'] = toolchain_version
78+
# LDFLAGS: Extra flags to give to compilers when they are supposed to
79+
# invoke the linker, ld, such as -L.
80+
env['LDFLAGS'] += ' -L' + self.ctx.get_libs_dir(self.arch)
81+
# LDLIBS: Library flags or names given to compilers when they are
82+
# supposed to invoke the linker.
83+
env['LDLIBS'] = '-lm'
10484

85+
# CCACHE
10586
ccache = ''
10687
if self.ctx.ccache and bool(int(environ.get('USE_CCACHE', '1'))):
10788
# print('ccache found, will optimize builds')
@@ -110,18 +91,15 @@ def get_env(self, with_flags_in_cc=True, clang=False):
11091
env['NDK_CCACHE'] = self.ctx.ccache
11192
env.update({k: v for k, v in environ.items() if k.startswith('CCACHE_')})
11293

113-
if clang:
114-
llvm_dirname = split(
115-
glob(join(self.ctx.ndk_dir, 'toolchains', 'llvm*'))[-1])[-1]
116-
clang_path = join(self.ctx.ndk_dir, 'toolchains', llvm_dirname,
117-
'prebuilt', build_platform, 'bin')
118-
environ['PATH'] = '{clang_path}:{path}'.format(
119-
clang_path=clang_path, path=environ['PATH'])
120-
exe = join(clang_path, 'clang')
121-
execxx = join(clang_path, 'clang++')
122-
else:
123-
exe = '{command_prefix}-gcc'.format(command_prefix=command_prefix)
124-
execxx = '{command_prefix}-g++'.format(command_prefix=command_prefix)
94+
# Compiler: `CC` and `CXX`
95+
llvm_dirname = split(
96+
glob(join(self.ctx.ndk_dir, 'toolchains', 'llvm*'))[-1])[-1]
97+
clang_path = join(self.ctx.ndk_dir, 'toolchains', llvm_dirname,
98+
'prebuilt', build_platform, 'bin')
99+
environ['PATH'] = '{clang_path}:{path}'.format(
100+
clang_path=clang_path, path=environ['PATH'])
101+
exe = join(clang_path, 'clang')
102+
execxx = join(clang_path, 'clang++')
125103

126104
cc = find_executable(exe, path=environ['PATH'])
127105
if cc is None:
@@ -149,20 +127,27 @@ def get_env(self, with_flags_in_cc=True, clang=False):
149127
execxx=execxx,
150128
ccache=ccache)
151129

130+
# Android's binaries
131+
command_prefix = self.command_prefix
152132
env['AR'] = '{}-ar'.format(command_prefix)
153133
env['RANLIB'] = '{}-ranlib'.format(command_prefix)
154-
env['LD'] = '{}-ld'.format(command_prefix)
155-
env['LDSHARED'] = env["CC"] + " -pthread -shared " +\
156-
"-Wl,-O1 -Wl,-Bsymbolic-functions "
157-
if self.ctx.python_recipe and self.ctx.python_recipe.from_crystax:
158-
# For crystax python, we can't use the host python headers:
159-
env["CFLAGS"] += ' -I{}/sources/python/{}/include/python/'.\
160-
format(self.ctx.ndk_dir, self.ctx.python_recipe.version[0:3])
161134
env['STRIP'] = '{}-strip --strip-unneeded'.format(command_prefix)
162-
env['MAKE'] = 'make -j5'
135+
env['MAKE'] = 'make -j{}'.format(str(cpu_count()))
163136
env['READELF'] = '{}-readelf'.format(command_prefix)
164137
env['NM'] = '{}-nm'.format(command_prefix)
138+
env['LD'] = '{}-ld'.format(command_prefix)
165139

140+
# Android's arch/toolchain
141+
env['ARCH'] = self.arch
142+
env['NDK_API'] = 'android-{}'.format(str(self.ctx.ndk_api))
143+
env['TOOLCHAIN_PREFIX'] = self.ctx.toolchain_prefix
144+
env['TOOLCHAIN_VERSION'] = self.ctx.toolchain_version
145+
146+
# Custom linker options
147+
env['LDSHARED'] = env['CC'] + (
148+
' -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions ')
149+
150+
# Host python (used by some recipes)
166151
hostpython_recipe = Recipe.get_recipe(
167152
'host' + self.ctx.python_recipe.name, self.ctx)
168153
env['BUILDLIB_PATH'] = join(
@@ -173,10 +158,11 @@ def get_env(self, with_flags_in_cc=True, clang=False):
173158

174159
env['PATH'] = environ['PATH']
175160

176-
env['ARCH'] = self.arch
177-
env['NDK_API'] = 'android-{}'.format(str(self.ctx.ndk_api))
178-
161+
# Specific flags for crystax (can we remove this?)
179162
if self.ctx.python_recipe and self.ctx.python_recipe.from_crystax:
163+
# For crystax python, we can't use the host python headers:
164+
env["CPPFLAGS"] += ' -I{}/sources/python/{}/include/python/'.\
165+
format(self.ctx.ndk_dir, self.ctx.python_recipe.version[0:3])
180166
env['CRYSTAX_PYTHON_VERSION'] = self.ctx.python_recipe.version
181167

182168
return env
@@ -191,8 +177,9 @@ class ArchARM(Arch):
191177
@property
192178
def target(self):
193179
target_data = self.command_prefix.split('-')
194-
return '-'.join(
195-
['armv7a', 'none', target_data[1], target_data[2]])
180+
return '{triplet}{ndk_api}'.format(
181+
triplet='-'.join(['armv7a', target_data[1], target_data[2]]),
182+
ndk_api=self.ctx.ndk_api)
196183

197184

198185
class ArchARMv7_a(ArchARM):

pythonforandroid/recommendations.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
from pythonforandroid.util import BuildInterruptingException
77

88
# We only check the NDK major version
9-
MIN_NDK_VERSION = 17
10-
MAX_NDK_VERSION = 17
9+
MIN_NDK_VERSION = 19
10+
MAX_NDK_VERSION = 19
1111

12-
RECOMMENDED_NDK_VERSION = '17c'
12+
RECOMMENDED_NDK_VERSION = '19b'
1313
OLD_NDK_MESSAGE = 'Older NDKs may not be compatible with all p4a features.'
1414
NEW_NDK_MESSAGE = 'Newer NDKs may not be fully supported by p4a.'
1515

0 commit comments

Comments
 (0)