-
Notifications
You must be signed in to change notification settings - Fork 1.9k
/
Copy patharchs.py
304 lines (254 loc) · 9.68 KB
/
archs.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
from os import environ
from os.path import join
from multiprocessing import cpu_count
import shutil
from pythonforandroid.recipe import Recipe
from pythonforandroid.util import BuildInterruptingException, build_platform
class Arch:
command_prefix = None
'''The prefix for NDK commands such as gcc.'''
arch = ""
'''Name of the arch such as: `armeabi-v7a`, `arm64-v8a`, `x86`...'''
arch_cflags = []
'''Specific arch `cflags`, expect to be overwrote in subclass if needed.'''
common_cflags = [
'-target {target}',
'-fomit-frame-pointer'
]
common_cppflags = [
'-DANDROID',
'-I{ctx.ndk.sysroot_include_dir}',
'-I{python_includes}',
]
common_ldflags = ['-L{ctx_libs_dir}']
common_ldlibs = ['-lm']
common_ldshared = [
'-pthread',
'-shared',
'-Wl,-O1',
'-Wl,-Bsymbolic-functions',
]
def __init__(self, ctx):
self.ctx = ctx
# Allows injecting additional linker paths used by any recipe.
# This can also be modified by recipes (like the librt recipe)
# to make sure that some sort of global resource is available &
# linked for all others.
self.extra_global_link_paths = []
def __str__(self):
return self.arch
@property
def ndk_lib_dir(self):
return join(self.ctx.ndk.sysroot_lib_dir, self.command_prefix)
@property
def ndk_lib_dir_versioned(self):
return join(self.ndk_lib_dir, str(self.ctx.ndk_api))
@property
def include_dirs(self):
return [
"{}/{}".format(
self.ctx.include_dir,
d.format(arch=self))
for d in self.ctx.include_dirs]
@property
def target(self):
# As of NDK r19, the toolchains installed by default with the
# NDK may be used in-place. The make_standalone_toolchain.py script
# is no longer needed for interfacing with arbitrary build systems.
# See: https://developer.android.com/ndk/guides/other_build_systems
return '{triplet}{ndk_api}'.format(
triplet=self.command_prefix, ndk_api=self.ctx.ndk_api
)
@property
def clang_exe(self):
"""Full path of the clang compiler depending on the android's ndk
version used."""
return self.get_clang_exe()
@property
def clang_exe_cxx(self):
"""Full path of the clang++ compiler depending on the android's ndk
version used."""
return self.get_clang_exe(plus_plus=True)
def get_clang_exe(self, with_target=False, plus_plus=False):
"""Returns the full path of the clang/clang++ compiler, supports two
kwargs:
- `with_target`: prepend `target` to clang
- `plus_plus`: will return the clang++ compiler (defaults to `False`)
"""
compiler = 'clang'
if with_target:
compiler = '{target}-{compiler}'.format(
target=self.target, compiler=compiler
)
if plus_plus:
compiler += '++'
return join(self.ctx.ndk.llvm_bin_dir, compiler)
def get_env(self, with_flags_in_cc=True):
env = {}
# HOME: User's home directory
#
# Many tools including p4a store outputs in the user's home
# directory. This is found from the HOME environment variable
# and falls back to the system account database. Setting HOME
# can be used to globally divert these tools to use a different
# path. Furthermore, in containerized environments the user may
# not exist in the account database, so if HOME isn't set than
# these tools will fail.
if 'HOME' in environ:
env['HOME'] = environ['HOME']
# CFLAGS/CXXFLAGS: the processor flags
env['CFLAGS'] = ' '.join(self.common_cflags).format(target=self.target)
if self.arch_cflags:
# each architecture may have has his own CFLAGS
env['CFLAGS'] += ' ' + ' '.join(self.arch_cflags)
env['CXXFLAGS'] = env['CFLAGS']
# CPPFLAGS (for macros and includes)
env['CPPFLAGS'] = ' '.join(self.common_cppflags).format(
ctx=self.ctx,
command_prefix=self.command_prefix,
python_includes=join(
self.ctx.get_python_install_dir(self.arch),
'include/python{}'.format(self.ctx.python_recipe.version[0:3]),
),
)
# LDFLAGS: Link the extra global link paths first before anything else
# (such that overriding system libraries with them is possible)
env['LDFLAGS'] = (
' '
+ " ".join(
[
"-L'"
+ link_path.replace("'", "'\"'\"'")
+ "'" # no shlex.quote in py2
for link_path in self.extra_global_link_paths
]
)
+ ' ' + ' '.join(self.common_ldflags).format(
ctx_libs_dir=self.ctx.get_libs_dir(self.arch)
)
)
# LDLIBS: Library flags or names given to compilers when they are
# supposed to invoke the linker.
env['LDLIBS'] = ' '.join(self.common_ldlibs)
# CCACHE
ccache = ''
if self.ctx.ccache and bool(int(environ.get('USE_CCACHE', '1'))):
# print('ccache found, will optimize builds')
ccache = self.ctx.ccache + ' '
env['USE_CCACHE'] = '1'
env['NDK_CCACHE'] = self.ctx.ccache
env.update(
{k: v for k, v in environ.items() if k.startswith('CCACHE_')}
)
# Compiler: `CC` and `CXX` (and make sure that the compiler exists)
env['PATH'] = self.ctx.env['PATH']
cc = shutil.which(self.clang_exe, path=env['PATH'])
if cc is None:
print('Searching path are: {!r}'.format(env['PATH']))
raise BuildInterruptingException(
'Couldn\'t find executable for CC. This indicates a '
'problem locating the {} executable in the Android '
'NDK, not that you don\'t have a normal compiler '
'installed. Exiting.'.format(self.clang_exe))
if with_flags_in_cc:
env['CC'] = '{ccache}{exe} {cflags}'.format(
exe=self.clang_exe,
ccache=ccache,
cflags=env['CFLAGS'])
env['CXX'] = '{ccache}{execxx} {cxxflags}'.format(
execxx=self.clang_exe_cxx,
ccache=ccache,
cxxflags=env['CXXFLAGS'])
else:
env['CC'] = '{ccache}{exe}'.format(
exe=self.clang_exe,
ccache=ccache)
env['CXX'] = '{ccache}{execxx}'.format(
execxx=self.clang_exe_cxx,
ccache=ccache)
# Android's LLVM binutils
env['AR'] = self.ctx.ndk.llvm_ar
env['RANLIB'] = self.ctx.ndk.llvm_ranlib
env['STRIP'] = f'{self.ctx.ndk.llvm_strip} --strip-unneeded'
env['READELF'] = self.ctx.ndk.llvm_readelf
env['OBJCOPY'] = self.ctx.ndk.llvm_objcopy
env['MAKE'] = 'make -j{}'.format(str(cpu_count()))
# Android's arch/toolchain
env['ARCH'] = self.arch
env['NDK_API'] = 'android-{}'.format(str(self.ctx.ndk_api))
# Custom linker options
env['LDSHARED'] = env['CC'] + ' ' + ' '.join(self.common_ldshared)
# Host python (used by some recipes)
hostpython_recipe = Recipe.get_recipe(
'host' + self.ctx.python_recipe.name, self.ctx)
env['BUILDLIB_PATH'] = join(
hostpython_recipe.get_build_dir(self.arch),
'native-build',
'build',
'lib.{}-{}'.format(
build_platform,
self.ctx.python_recipe.major_minor_version_string,
),
)
# for reproducible builds
if 'SOURCE_DATE_EPOCH' in environ:
for k in 'LC_ALL TZ SOURCE_DATE_EPOCH PYTHONHASHSEED BUILD_DATE BUILD_TIME'.split():
if k in environ:
env[k] = environ[k]
return env
class ArchARM(Arch):
arch = "armeabi"
command_prefix = 'arm-linux-androideabi'
@property
def target(self):
target_data = self.command_prefix.split('-')
return '{triplet}{ndk_api}'.format(
triplet='-'.join(['armv7a', target_data[1], target_data[2]]),
ndk_api=self.ctx.ndk_api,
)
class ArchARMv7_a(ArchARM):
arch = 'armeabi-v7a'
arch_cflags = [
'-march=armv7-a',
'-mfloat-abi=softfp',
'-mfpu=vfp',
'-mthumb',
'-fPIC',
]
class Archx86(Arch):
arch = 'x86'
command_prefix = 'i686-linux-android'
arch_cflags = [
'-march=i686',
'-mssse3',
'-mfpmath=sse',
'-m32',
'-fPIC',
]
class Archx86_64(Arch):
arch = 'x86_64'
command_prefix = 'x86_64-linux-android'
arch_cflags = [
'-march=x86-64',
'-msse4.2',
'-mpopcnt',
'-m64',
'-fPIC',
]
class ArchAarch_64(Arch):
arch = 'arm64-v8a'
command_prefix = 'aarch64-linux-android'
arch_cflags = [
'-march=armv8-a',
'-fPIC'
# '-I' + join(dirname(__file__), 'includes', 'arm64-v8a'),
]
# Note: This `EXTRA_CFLAGS` below should target the commented `include`
# above in `arch_cflags`. The original lines were added during the Sdl2's
# bootstrap creation, and modified/commented during the migration to the
# NDK r19 build system, because it seems that we don't need it anymore,
# do we need them?
# def get_env(self, with_flags_in_cc=True):
# env = super().get_env(with_flags_in_cc)
# env['EXTRA_CFLAGS'] = self.arch_cflags[-1]
# return env