Skip to content

Commit 61314e9

Browse files
committed
Added pythonforandroid.androidndk.AndroidNDK + some changes needed in order to support build on Apple Silicon macs.
1 parent 44d3591 commit 61314e9

36 files changed

+367
-263
lines changed

.github/workflows/push.yml

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,21 +86,31 @@ jobs:
8686
matrix:
8787
include:
8888
- runs_on: macos-latest
89+
ndk_version: '23b'
90+
openssl_pkg_config_path: /usr/local/opt/[email protected]/lib/pkgconfig
8991
- runs_on: apple-silicon-m1
9092
run_wrapper: arch -arm64 bash --noprofile --norc -eo pipefail {0}
93+
ndk_version: '24'
94+
openssl_pkg_config_path: /opt/homebrew/opt/[email protected]/lib/pkgconfig
9195
env:
9296
ANDROID_HOME: ${HOME}/.android
9397
ANDROID_SDK_ROOT: ${HOME}/.android/android-sdk
9498
ANDROID_SDK_HOME: ${HOME}/.android/android-sdk
9599
ANDROID_NDK_HOME: ${HOME}/.android/android-ndk
100+
ANDROID_NDK_VERSION: ${{ matrix.ndk_version }}
101+
PKG_CONFIG_PATH: ${{ matrix.openssl_pkg_config_path }}
96102
steps:
97103
- name: Checkout python-for-android
98104
uses: actions/checkout@v2
105+
- uses: actions/setup-java@v3
106+
with:
107+
distribution: 'temurin'
108+
java-version: '17'
99109
- name: Install dependencies
100110
run: |
101111
source ci/osx_ci.sh
102112
arm64_set_path_and_python_version 3.9.7
103-
brew install autoconf automake libtool openssl pkg-config
113+
brew install autoconf automake libtool openssl@1.1 pkg-config cmake
104114
make --file ci/makefiles/osx.mk
105115
- name: Build multi-arch apk Python 3 (armeabi-v7a, arm64-v8a, x86_64, x86)
106116
run: |
@@ -147,21 +157,31 @@ jobs:
147157
matrix:
148158
include:
149159
- runs_on: macos-latest
160+
ndk_version: '23b'
161+
openssl_pkg_config_path: /usr/local/opt/[email protected]/lib/pkgconfig
150162
- runs_on: apple-silicon-m1
151163
run_wrapper: arch -arm64 bash --noprofile --norc -eo pipefail {0}
164+
ndk_version: '24'
165+
openssl_pkg_config_path: /opt/homebrew/opt/[email protected]/lib/pkgconfig
152166
env:
153167
ANDROID_HOME: ${HOME}/.android
154168
ANDROID_SDK_ROOT: ${HOME}/.android/android-sdk
155169
ANDROID_SDK_HOME: ${HOME}/.android/android-sdk
156170
ANDROID_NDK_HOME: ${HOME}/.android/android-ndk
171+
ANDROID_NDK_VERSION: ${{ matrix.ndk_version }}
172+
PKG_CONFIG_PATH: ${{ matrix.openssl_pkg_config_path }}
157173
steps:
158174
- name: Checkout python-for-android
159175
uses: actions/checkout@v2
176+
- uses: actions/setup-java@v3
177+
with:
178+
distribution: 'temurin'
179+
java-version: '17'
160180
- name: Install dependencies
161181
run: |
162182
source ci/osx_ci.sh
163183
arm64_set_path_and_python_version 3.9.7
164-
brew install autoconf automake libtool openssl pkg-config
184+
brew install autoconf automake libtool openssl@1.1 pkg-config cmake
165185
make --file ci/makefiles/osx.mk
166186
- name: Build multi-arch apk Python 3 (armeabi-v7a, arm64-v8a, x86_64, x86)
167187
run: |
@@ -205,25 +225,35 @@ jobs:
205225
matrix:
206226
include:
207227
- runs_on: macos-latest
228+
ndk_version: '23b'
229+
openssl_pkg_config_path: /usr/local/opt/[email protected]/lib/pkgconfig
208230
- runs_on: apple-silicon-m1
209231
run_wrapper: arch -arm64 bash --noprofile --norc -eo pipefail {0}
232+
ndk_version: '24'
233+
openssl_pkg_config_path: /opt/homebrew/opt/[email protected]/lib/pkgconfig
210234
env:
211235
ANDROID_HOME: ${HOME}/.android
212236
ANDROID_SDK_ROOT: ${HOME}/.android/android-sdk
213237
ANDROID_SDK_HOME: ${HOME}/.android/android-sdk
214238
ANDROID_NDK_HOME: ${HOME}/.android/android-ndk
239+
ANDROID_NDK_VERSION: ${{ matrix.ndk_version }}
240+
PKG_CONFIG_PATH: ${{ matrix.openssl_pkg_config_path }}
215241
steps:
216242
- name: Checkout python-for-android
217243
uses: actions/checkout@v2
218244
with:
219245
fetch-depth: 0
246+
- uses: actions/setup-java@v3
247+
with:
248+
distribution: 'temurin'
249+
java-version: '17'
220250
- name: Install dependencies
221251
run: |
222252
source ci/osx_ci.sh
223253
arm64_set_path_and_python_version 3.9.7
224-
brew install autoconf automake libtool openssl pkg-config
254+
brew install autoconf automake libtool openssl@1.1 pkg-config cmake
225255
make --file ci/makefiles/osx.mk
226-
- name: Build multi-arch apk Python 3 (armeabi-v7a, arm64-v8a, x86_64, x86)
256+
- name: Rebuild updated recipes
227257
run: |
228258
source ci/osx_ci.sh
229259
arm64_set_path_and_python_version 3.9.7

ci/makefiles/osx.mk

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,7 @@
33
# The following variable/s can be override when running the file
44
ANDROID_HOME ?= $(HOME)/.android
55

6-
all: install_java upgrade_cython install_android_ndk_sdk install_p4a
7-
8-
install_java:
9-
brew tap adoptopenjdk/openjdk
10-
brew install --cask adoptopenjdk13
11-
/usr/libexec/java_home -V
6+
all: upgrade_cython install_android_ndk_sdk install_p4a
127

138
upgrade_cython:
149
pip3 install --upgrade Cython

ci/rebuild_updated_recipes.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ def build(target_python, requirements):
6262
for line in sh.python(
6363
'setup.py', 'apk', '--sdk-dir', android_sdk_home,
6464
'--ndk-dir', android_ndk_home, '--requirements',
65-
requirements, _err_to_out=True, _iter=True):
65+
requirements, '--arch', 'arm64-v8a', '--arch', 'armeabi-v7a',
66+
_err_to_out=True, _iter=True):
6667
print(line)
6768

6869

pythonforandroid/androidndk.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import sys
2+
import os
3+
4+
5+
class AndroidNDK(object):
6+
"""
7+
This class is used to get the current NDK information.
8+
"""
9+
10+
ndk_dir = ""
11+
12+
def __init__(self, ndk_dir):
13+
self.ndk_dir = ndk_dir
14+
15+
@property
16+
def host_tag(self):
17+
"""
18+
Returns the host tag for the current system.
19+
Note: The host tag is ``darwin-x86_64`` even on Apple Silicon macs.
20+
"""
21+
return f"{sys.platform}-x86_64"
22+
23+
@property
24+
def llvm_prebuilt_dir(self):
25+
return os.path.join(
26+
self.ndk_dir, "toolchains", "llvm", "prebuilt", self.host_tag
27+
)
28+
29+
@property
30+
def llvm_bin_dir(self):
31+
return os.path.join(self.llvm_prebuilt_dir, "bin")
32+
33+
@property
34+
def clang(self):
35+
return os.path.join(self.llvm_bin_dir, "clang")
36+
37+
@property
38+
def clang_cxx(self):
39+
return os.path.join(self.llvm_bin_dir, "clang++")
40+
41+
@property
42+
def llvm_binutils_prefix(self):
43+
return os.path.join(self.llvm_bin_dir, "llvm-")
44+
45+
@property
46+
def llvm_ar(self):
47+
return f"{self.llvm_binutils_prefix}ar"
48+
49+
@property
50+
def llvm_ranlib(self):
51+
return f"{self.llvm_binutils_prefix}ranlib"
52+
53+
@property
54+
def llvm_objcopy(self):
55+
return f"{self.llvm_binutils_prefix}objcopy"
56+
57+
@property
58+
def llvm_objdump(self):
59+
return f"{self.llvm_binutils_prefix}objdump"
60+
61+
@property
62+
def llvm_readelf(self):
63+
return f"{self.llvm_binutils_prefix}readelf"
64+
65+
@property
66+
def llvm_strip(self):
67+
return f"{self.llvm_binutils_prefix}strip"
68+
69+
@property
70+
def sysroot(self):
71+
return os.path.join(self.llvm_prebuilt_dir, "sysroot")
72+
73+
@property
74+
def sysroot_include_dir(self):
75+
return os.path.join(self.sysroot, "usr", "include")
76+
77+
@property
78+
def sysroot_lib_dir(self):
79+
return os.path.join(self.sysroot, "usr", "lib")
80+
81+
@property
82+
def libcxx_include_dir(self):
83+
return os.path.join(self.sysroot_include_dir, "c++", "v1")

pythonforandroid/archs.py

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class Arch:
2525

2626
common_cppflags = [
2727
'-DANDROID',
28-
'-I{ctx.ndk_sysroot}/usr/include',
28+
'-I{ctx.ndk.sysroot_include_dir}',
2929
'-I{python_includes}',
3030
]
3131

@@ -54,7 +54,11 @@ def __str__(self):
5454

5555
@property
5656
def ndk_lib_dir(self):
57-
return join(self.ctx.ndk_sysroot, 'usr', 'lib', self.command_prefix, str(self.ctx.ndk_api))
57+
return join(self.ctx.ndk.sysroot_lib_dir, self.command_prefix)
58+
59+
@property
60+
def ndk_lib_dir_versioned(self):
61+
return join(self.ndk_lib_dir, str(self.ctx.ndk_api))
5862

5963
@property
6064
def include_dirs(self):
@@ -74,18 +78,6 @@ def target(self):
7478
triplet=self.command_prefix, ndk_api=self.ctx.ndk_api
7579
)
7680

77-
@property
78-
def clang_path(self):
79-
"""Full path of the clang compiler"""
80-
return join(
81-
self.ctx.ndk_dir,
82-
'toolchains',
83-
'llvm',
84-
'prebuilt',
85-
build_platform,
86-
'bin',
87-
)
88-
8981
@property
9082
def clang_exe(self):
9183
"""Full path of the clang compiler depending on the android's ndk
@@ -112,7 +104,7 @@ def get_clang_exe(self, with_target=False, plus_plus=False):
112104
)
113105
if plus_plus:
114106
compiler += '++'
115-
return join(self.clang_path, compiler)
107+
return join(self.ctx.ndk.llvm_bin_dir, compiler)
116108

117109
def get_env(self, with_flags_in_cc=True):
118110
env = {}
@@ -195,11 +187,11 @@ def get_env(self, with_flags_in_cc=True):
195187
ccache=ccache)
196188

197189
# Android's LLVM binutils
198-
env['AR'] = f'{self.clang_path}/llvm-ar'
199-
env['RANLIB'] = f'{self.clang_path}/llvm-ranlib'
200-
env['STRIP'] = f'{self.clang_path}/llvm-strip --strip-unneeded'
201-
env['READELF'] = f'{self.clang_path}/llvm-readelf'
202-
env['OBJCOPY'] = f'{self.clang_path}/llvm-objcopy'
190+
env['AR'] = self.ctx.ndk.llvm_ar
191+
env['RANLIB'] = self.ctx.ndk.llvm_ranlib
192+
env['STRIP'] = f'{self.ctx.ndk.llvm_strip} --strip-unneeded'
193+
env['READELF'] = self.ctx.ndk.llvm_readelf
194+
env['OBJCOPY'] = self.ctx.ndk.llvm_objcopy
203195

204196
env['MAKE'] = 'make -j{}'.format(str(cpu_count()))
205197

pythonforandroid/build.py

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import copy
66
import os
77
import glob
8-
import sys
98
import re
109
import sh
1110
import shutil
@@ -23,20 +22,7 @@
2322
from pythonforandroid.recommendations import (
2423
check_ndk_version, check_target_api, check_ndk_api,
2524
RECOMMENDED_NDK_API, RECOMMENDED_TARGET_API)
26-
from pythonforandroid.util import build_platform
27-
28-
29-
def get_ndk_standalone(ndk_dir):
30-
return join(ndk_dir, 'toolchains', 'llvm', 'prebuilt', build_platform)
31-
32-
33-
def get_ndk_sysroot(ndk_dir):
34-
sysroot = join(get_ndk_standalone(ndk_dir), 'sysroot')
35-
sysroot_exists = True
36-
if not exists(sysroot):
37-
warning("sysroot doesn't exist: {}".format(sysroot))
38-
sysroot_exists = False
39-
return sysroot, sysroot_exists
25+
from pythonforandroid.androidndk import AndroidNDK
4026

4127

4228
def get_targets(sdk_dir):
@@ -97,9 +83,7 @@ class Context:
9783

9884
ccache = None # whether to use ccache
9985

100-
ndk_standalone = None
101-
ndk_sysroot = None
102-
ndk_include_dir = None # usr/include
86+
ndk = None
10387

10488
bootstrap = None
10589
bootstrap_build_dir = None
@@ -326,7 +310,6 @@ def prepare_build_environment(self,
326310
if ndk_dir is None:
327311
raise BuildInterruptingException('Android NDK dir was not specified')
328312
self.ndk_dir = realpath(ndk_dir)
329-
330313
check_ndk_version(ndk_dir)
331314

332315
ndk_api = None
@@ -346,6 +329,8 @@ def prepare_build_environment(self,
346329

347330
check_ndk_api(ndk_api, self.android_api)
348331

332+
self.ndk = AndroidNDK(self.ndk_dir)
333+
349334
# path to some tools
350335
self.ccache = sh.which("ccache")
351336
if not self.ccache:
@@ -360,17 +345,9 @@ def prepare_build_environment(self,
360345
' a python 3 target (which is the default)'
361346
' then THINGS WILL BREAK.')
362347

363-
py_platform = sys.platform
364-
if py_platform in ['linux2', 'linux3']:
365-
py_platform = 'linux'
366-
367-
self.ndk_standalone = get_ndk_standalone(self.ndk_dir)
368-
self.ndk_sysroot, ndk_sysroot_exists = get_ndk_sysroot(self.ndk_dir)
369-
self.ndk_include_dir = join(self.ndk_sysroot, 'usr', 'include')
370-
371348
self.env["PATH"] = ":".join(
372349
[
373-
f"{ndk_dir}/toolchains/llvm/prebuilt/{py_platform}-x86_64/bin",
350+
self.ndk.llvm_bin_dir,
374351
ndk_dir,
375352
f"{sdk_dir}/tools",
376353
environ.get("PATH"),

pythonforandroid/recipe.py

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -135,24 +135,9 @@ class Recipe(with_metaclass(RecipeMeta)):
135135
starting from NDK r18 the `gnustl_shared` lib has been deprecated.
136136
'''
137137

138-
stl_lib_source = '{ctx.ndk_dir}/sources/cxx-stl/llvm-libc++'
139-
'''
140-
The source directory of the selected stl lib, defined in property
141-
`stl_lib_name`
142-
'''
143-
144-
@property
145-
def stl_include_dir(self):
146-
return join(self.stl_lib_source.format(ctx=self.ctx), 'include')
147-
148-
def get_stl_lib_dir(self, arch):
149-
return join(
150-
self.stl_lib_source.format(ctx=self.ctx), 'libs', arch.arch
151-
)
152-
153138
def get_stl_library(self, arch):
154139
return join(
155-
self.get_stl_lib_dir(arch),
140+
arch.ndk_lib_dir,
156141
'lib{name}.so'.format(name=self.stl_lib_name),
157142
)
158143

@@ -510,14 +495,14 @@ def get_recipe_env(self, arch=None, with_flags_in_cc=True):
510495

511496
if self.need_stl_shared:
512497
env['CPPFLAGS'] = env.get('CPPFLAGS', '')
513-
env['CPPFLAGS'] += ' -I{}'.format(self.stl_include_dir)
498+
env['CPPFLAGS'] += ' -I{}'.format(self.ctx.ndk.libcxx_include_dir)
514499

515500
env['CXXFLAGS'] = env['CFLAGS'] + ' -frtti -fexceptions'
516501

517502
if with_flags_in_cc:
518503
env['CXX'] += ' -frtti -fexceptions'
519504

520-
env['LDFLAGS'] += ' -L{}'.format(self.get_stl_lib_dir(arch))
505+
env['LDFLAGS'] += ' -L{}'.format(arch.ndk_lib_dir)
521506
env['LIBS'] = env.get('LIBS', '') + " -l{}".format(
522507
self.stl_lib_name
523508
)

0 commit comments

Comments
 (0)