Skip to content

Commit

Permalink
Added pythonforandroid.androidndk.AndroidNDK + some changes needed in…
Browse files Browse the repository at this point in the history
… order to support build on Apple Silicon macs.
  • Loading branch information
misl6 committed Apr 25, 2022
1 parent 846d80d commit a018304
Show file tree
Hide file tree
Showing 36 changed files with 366 additions and 262 deletions.
36 changes: 33 additions & 3 deletions .github/workflows/push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,21 +97,31 @@ jobs:
matrix:
include:
- runs_on: macos-latest
ndk_version: '23b'
openssl_pkg_config_path: /usr/local/opt/openssl@1.1/lib/pkgconfig
- runs_on: apple-silicon-m1
run_wrapper: arch -arm64 bash --noprofile --norc -eo pipefail {0}
ndk_version: '24'
openssl_pkg_config_path: /opt/homebrew/opt/openssl@1.1/lib/pkgconfig
env:
ANDROID_HOME: ${HOME}/.android
ANDROID_SDK_ROOT: ${HOME}/.android/android-sdk
ANDROID_SDK_HOME: ${HOME}/.android/android-sdk
ANDROID_NDK_HOME: ${HOME}/.android/android-ndk
ANDROID_NDK_VERSION: ${{ matrix.ndk_version }}
PKG_CONFIG_PATH: ${{ matrix.openssl_pkg_config_path }}
steps:
- name: Checkout python-for-android
uses: actions/checkout@v2
- uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
- name: Install dependencies
run: |
source ci/osx_ci.sh
arm64_set_path_and_python_version 3.9.7
brew install autoconf automake libtool openssl pkg-config
brew install autoconf automake libtool openssl@1.1 pkg-config cmake
make --file ci/makefiles/osx.mk
- name: Build multi-arch apk Python 3 (armeabi-v7a, arm64-v8a, x86_64, x86)
run: |
Expand Down Expand Up @@ -172,21 +182,31 @@ jobs:
matrix:
include:
- runs_on: macos-latest
ndk_version: '23b'
openssl_pkg_config_path: /usr/local/opt/openssl@1.1/lib/pkgconfig
- runs_on: apple-silicon-m1
run_wrapper: arch -arm64 bash --noprofile --norc -eo pipefail {0}
ndk_version: '24'
openssl_pkg_config_path: /opt/homebrew/opt/openssl@1.1/lib/pkgconfig
env:
ANDROID_HOME: ${HOME}/.android
ANDROID_SDK_ROOT: ${HOME}/.android/android-sdk
ANDROID_SDK_HOME: ${HOME}/.android/android-sdk
ANDROID_NDK_HOME: ${HOME}/.android/android-ndk
ANDROID_NDK_VERSION: ${{ matrix.ndk_version }}
PKG_CONFIG_PATH: ${{ matrix.openssl_pkg_config_path }}
steps:
- name: Checkout python-for-android
uses: actions/checkout@v2
- uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
- name: Install dependencies
run: |
source ci/osx_ci.sh
arm64_set_path_and_python_version 3.9.7
brew install autoconf automake libtool openssl pkg-config
brew install autoconf automake libtool openssl@1.1 pkg-config cmake
make --file ci/makefiles/osx.mk
- name: Build multi-arch aab Python 3 (armeabi-v7a, arm64-v8a, x86_64, x86)
run: |
Expand Down Expand Up @@ -237,23 +257,33 @@ jobs:
matrix:
include:
- runs_on: macos-latest
ndk_version: '23b'
openssl_pkg_config_path: /usr/local/opt/openssl@1.1/lib/pkgconfig
- runs_on: apple-silicon-m1
run_wrapper: arch -arm64 bash --noprofile --norc -eo pipefail {0}
ndk_version: '24'
openssl_pkg_config_path: /opt/homebrew/opt/openssl@1.1/lib/pkgconfig
env:
ANDROID_HOME: ${HOME}/.android
ANDROID_SDK_ROOT: ${HOME}/.android/android-sdk
ANDROID_SDK_HOME: ${HOME}/.android/android-sdk
ANDROID_NDK_HOME: ${HOME}/.android/android-ndk
ANDROID_NDK_VERSION: ${{ matrix.ndk_version }}
PKG_CONFIG_PATH: ${{ matrix.openssl_pkg_config_path }}
steps:
- name: Checkout python-for-android
uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
- name: Install dependencies
run: |
source ci/osx_ci.sh
arm64_set_path_and_python_version 3.9.7
brew install autoconf automake libtool openssl pkg-config
brew install autoconf automake libtool openssl@1.1 pkg-config cmake
make --file ci/makefiles/osx.mk
- name: Rebuild updated recipes
run: |
Expand Down
7 changes: 1 addition & 6 deletions ci/makefiles/osx.mk
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@
# The following variable/s can be override when running the file
ANDROID_HOME ?= $(HOME)/.android

all: install_java upgrade_cython install_android_ndk_sdk install_p4a

install_java:
brew tap adoptopenjdk/openjdk
brew install --cask adoptopenjdk13
/usr/libexec/java_home -V
all: upgrade_cython install_android_ndk_sdk install_p4a

upgrade_cython:
pip3 install --upgrade Cython
Expand Down
3 changes: 2 additions & 1 deletion ci/rebuild_updated_recipes.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ def build(target_python, requirements):
for line in sh.python(
'setup.py', 'apk', '--sdk-dir', android_sdk_home,
'--ndk-dir', android_ndk_home, '--requirements',
requirements, _err_to_out=True, _iter=True):
requirements, '--arch', 'arm64-v8a', '--arch', 'armeabi-v7a',
_err_to_out=True, _iter=True):
print(line)


Expand Down
83 changes: 83 additions & 0 deletions pythonforandroid/androidndk.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import sys
import os


class AndroidNDK(object):
"""
This class is used to get the current NDK information.
"""

ndk_dir = ""

def __init__(self, ndk_dir):
self.ndk_dir = ndk_dir

@property
def host_tag(self):
"""
Returns the host tag for the current system.
Note: The host tag is ``darwin-x86_64`` even on Apple Silicon macs.
"""
return f"{sys.platform}-x86_64"

@property
def llvm_prebuilt_dir(self):
return os.path.join(
self.ndk_dir, "toolchains", "llvm", "prebuilt", self.host_tag
)

@property
def llvm_bin_dir(self):
return os.path.join(self.llvm_prebuilt_dir, "bin")

@property
def clang(self):
return os.path.join(self.llvm_bin_dir, "clang")

@property
def clang_cxx(self):
return os.path.join(self.llvm_bin_dir, "clang++")

@property
def llvm_binutils_prefix(self):
return os.path.join(self.llvm_bin_dir, "llvm-")

@property
def llvm_ar(self):
return f"{self.llvm_binutils_prefix}ar"

@property
def llvm_ranlib(self):
return f"{self.llvm_binutils_prefix}ranlib"

@property
def llvm_objcopy(self):
return f"{self.llvm_binutils_prefix}objcopy"

@property
def llvm_objdump(self):
return f"{self.llvm_binutils_prefix}objdump"

@property
def llvm_readelf(self):
return f"{self.llvm_binutils_prefix}readelf"

@property
def llvm_strip(self):
return f"{self.llvm_binutils_prefix}strip"

@property
def sysroot(self):
return os.path.join(self.llvm_prebuilt_dir, "sysroot")

@property
def sysroot_include_dir(self):
return os.path.join(self.sysroot, "usr", "include")

@property
def sysroot_lib_dir(self):
return os.path.join(self.sysroot, "usr", "lib")

@property
def libcxx_include_dir(self):
return os.path.join(self.sysroot_include_dir, "c++", "v1")
32 changes: 12 additions & 20 deletions pythonforandroid/archs.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class Arch:

common_cppflags = [
'-DANDROID',
'-I{ctx.ndk_sysroot}/usr/include',
'-I{ctx.ndk.sysroot_include_dir}',
'-I{python_includes}',
]

Expand Down Expand Up @@ -54,7 +54,11 @@ def __str__(self):

@property
def ndk_lib_dir(self):
return join(self.ctx.ndk_sysroot, 'usr', 'lib', self.command_prefix, str(self.ctx.ndk_api))
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):
Expand All @@ -74,18 +78,6 @@ def target(self):
triplet=self.command_prefix, ndk_api=self.ctx.ndk_api
)

@property
def clang_path(self):
"""Full path of the clang compiler"""
return join(
self.ctx.ndk_dir,
'toolchains',
'llvm',
'prebuilt',
build_platform,
'bin',
)

@property
def clang_exe(self):
"""Full path of the clang compiler depending on the android's ndk
Expand All @@ -112,7 +104,7 @@ def get_clang_exe(self, with_target=False, plus_plus=False):
)
if plus_plus:
compiler += '++'
return join(self.clang_path, compiler)
return join(self.ctx.ndk.llvm_bin_dir, compiler)

def get_env(self, with_flags_in_cc=True):
env = {}
Expand Down Expand Up @@ -195,11 +187,11 @@ def get_env(self, with_flags_in_cc=True):
ccache=ccache)

# Android's LLVM binutils
env['AR'] = f'{self.clang_path}/llvm-ar'
env['RANLIB'] = f'{self.clang_path}/llvm-ranlib'
env['STRIP'] = f'{self.clang_path}/llvm-strip --strip-unneeded'
env['READELF'] = f'{self.clang_path}/llvm-readelf'
env['OBJCOPY'] = f'{self.clang_path}/llvm-objcopy'
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()))

Expand Down
33 changes: 5 additions & 28 deletions pythonforandroid/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import copy
import os
import glob
import sys
import re
import sh
import shutil
Expand All @@ -23,20 +22,7 @@
from pythonforandroid.recommendations import (
check_ndk_version, check_target_api, check_ndk_api,
RECOMMENDED_NDK_API, RECOMMENDED_TARGET_API)
from pythonforandroid.util import build_platform


def get_ndk_standalone(ndk_dir):
return join(ndk_dir, 'toolchains', 'llvm', 'prebuilt', build_platform)


def get_ndk_sysroot(ndk_dir):
sysroot = join(get_ndk_standalone(ndk_dir), 'sysroot')
sysroot_exists = True
if not exists(sysroot):
warning("sysroot doesn't exist: {}".format(sysroot))
sysroot_exists = False
return sysroot, sysroot_exists
from pythonforandroid.androidndk import AndroidNDK


def get_targets(sdk_dir):
Expand Down Expand Up @@ -97,9 +83,7 @@ class Context:

ccache = None # whether to use ccache

ndk_standalone = None
ndk_sysroot = None
ndk_include_dir = None # usr/include
ndk = None

bootstrap = None
bootstrap_build_dir = None
Expand Down Expand Up @@ -326,7 +310,6 @@ def prepare_build_environment(self,
if ndk_dir is None:
raise BuildInterruptingException('Android NDK dir was not specified')
self.ndk_dir = realpath(ndk_dir)

check_ndk_version(ndk_dir)

ndk_api = None
Expand All @@ -346,6 +329,8 @@ def prepare_build_environment(self,

check_ndk_api(ndk_api, self.android_api)

self.ndk = AndroidNDK(self.ndk_dir)

# path to some tools
self.ccache = sh.which("ccache")
if not self.ccache:
Expand All @@ -360,17 +345,9 @@ def prepare_build_environment(self,
' a python 3 target (which is the default)'
' then THINGS WILL BREAK.')

py_platform = sys.platform
if py_platform in ['linux2', 'linux3']:
py_platform = 'linux'

self.ndk_standalone = get_ndk_standalone(self.ndk_dir)
self.ndk_sysroot, ndk_sysroot_exists = get_ndk_sysroot(self.ndk_dir)
self.ndk_include_dir = join(self.ndk_sysroot, 'usr', 'include')

self.env["PATH"] = ":".join(
[
f"{ndk_dir}/toolchains/llvm/prebuilt/{py_platform}-x86_64/bin",
self.ndk.llvm_bin_dir,
ndk_dir,
f"{sdk_dir}/tools",
environ.get("PATH"),
Expand Down
21 changes: 3 additions & 18 deletions pythonforandroid/recipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,24 +135,9 @@ class Recipe(with_metaclass(RecipeMeta)):
starting from NDK r18 the `gnustl_shared` lib has been deprecated.
'''

stl_lib_source = '{ctx.ndk_dir}/sources/cxx-stl/llvm-libc++'
'''
The source directory of the selected stl lib, defined in property
`stl_lib_name`
'''

@property
def stl_include_dir(self):
return join(self.stl_lib_source.format(ctx=self.ctx), 'include')

def get_stl_lib_dir(self, arch):
return join(
self.stl_lib_source.format(ctx=self.ctx), 'libs', arch.arch
)

def get_stl_library(self, arch):
return join(
self.get_stl_lib_dir(arch),
arch.ndk_lib_dir,
'lib{name}.so'.format(name=self.stl_lib_name),
)

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

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

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

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

env['LDFLAGS'] += ' -L{}'.format(self.get_stl_lib_dir(arch))
env['LDFLAGS'] += ' -L{}'.format(arch.ndk_lib_dir)
env['LIBS'] = env.get('LIBS', '') + " -l{}".format(
self.stl_lib_name
)
Expand Down
Loading

0 comments on commit a018304

Please sign in to comment.