Skip to content

Initial Android support #262

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/adb-emu.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/sh
adb push "$1" /data/local/tmp/ 1>/dev/null 2>/dev/null
if [ $# -eq 1 ]; then
adb shell /data/local/tmp/$(basename $1)
elif [ $# -eq 3 ]; then
adb push "$2" /data/local/tmp/ 1>/dev/null 2>/dev/null
adb shell /data/local/tmp/$(basename $1) /data/local/tmp/$(basename $2) /data/local/tmp/$(basename $3)
adb pull /data/local/tmp/$(basename $3) "$3" 1>/dev/null 2>/dev/null
fi
88 changes: 88 additions & 0 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
name: "Android bulds"

on: [push, pull_request]

jobs:
build-android:
name: ${{ matrix.ndk-arch }} on ${{ matrix.arch }} Android
runs-on: macos-11
strategy:
matrix:
ndk-arch: [x86_64]
arch: [x86_64]
api-level: [21]
target: [default]
include:
- ndk-arch: arm64-v8a
arch: x86_64
api-level: 30
target: google_apis
- ndk-arch: x86
arch: x86
api-level: 21
target: default
- ndk-arch: armeabi-v7a
arch: x86_64
api-level: 30
target: google_apis

steps:
- name: checkout
uses: actions/checkout@v2

- uses: actions/cache@v2
id: avd-cache
with:
path: |
~/.android/avd/*
~/.android/adb*
~/.android/debug.keystore
key: avd-${{ matrix.api-level }}-${{ matrix.target }}-${{ matrix.arch }}

- name: run emulator to generate snapshot for caching
if: steps.avd-cache.outputs.cache-hit != 'true'
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: ${{ matrix.api-level }}
target: ${{ matrix.target }}
arch: ${{ matrix.arch }}
profile: Galaxy Nexus
cores: 2
sdcard-path-or-size: 100M
emulator-build: 7425822 # https://github.com/ReactiveCircus/android-emulator-runner/issues/160
avd-name: test
force-avd-creation: false
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: false
working-directory: ./
ndk: 21.0.6113669
cmake: 3.10.2.4988404
script: echo "Generated AVD snapshot for caching."

- name: run action
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: ${{ matrix.api-level }}
target: ${{ matrix.target }}
arch: ${{ matrix.arch }}
profile: Galaxy Nexus
cores: 2
ram-size: 2048M
sdcard-path-or-size: 100M
emulator-build: 7425822 # https://github.com/ReactiveCircus/android-emulator-runner/issues/160
avd-name: test
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true
working-directory: ./
ndk: 21.0.6113669
cmake: 3.10.2.4988404
script: |
# ls -lR /Users/runner/Library/Android/sdk
adb devices
mkdir ../build
mkdir ../install-prefix
cd ../build
cmake -DCMAKE_INSTALL_PREFIX:PATH=../../install-prefix -DCMAKE_TOOLCHAIN_FILE=/Users/runner/Library/Android/sdk/ndk-bundle/build/cmake/android.toolchain.cmake -DANDROID_ABI=${{ matrix.ndk-arch }} -DCMAKE_CROSSCOMPILING_EMULATOR=/Users/runner/work/python-cmake-buildsystem/python-cmake-buildsystem/.github/workflows/adb-emu.sh -DANDROID_ALLOW_UNDEFINED_SYMBOLS=On -DENABLE_DECIMAL=Off -DENABLE_CTYPES=Off -DENABLE_CODECS_JP=OFF -DENABLE_CODECS_KR=OFF -DENABLE_CODECS_TW=OFF -DENABLE_MULTIBYTECODEC=OFF -DENABLE_CODECS_CN=OFF -DENABLE_CODECS_HK=OFF -DENABLE_CODECS_ISO2022=OFF -DBUILD_EXTENSIONS_AS_BUILTIN=On -DANDROID_PLATFORM=android-21 ../python-cmake-buildsystem/
cmake --build . -- VERBOSE=1
cmake --build . --target install
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,7 @@ if(UNIX)

# Makefile
set(MAKEFILE_LDSHARED_FLAGS "-shared")
if(APPLE)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(MAKEFILE_LDSHARED_FLAGS "-dynamiclib -headerpad_max_install_names -undefined dynamic_lookup")
endif()
configure_file(cmake/makefile-variables.in
Expand Down
26 changes: 26 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,32 @@ options on the commandline with `-DOPTION=VALUE`, or use the "ccmake" gui.
Then, this variable is used to initialize `CMAKE_OSX_SYSROOT`, `CMAKE_OSX_DEPLOYMENT_TARGET`
and `MACOSX_DEPLOYMENT_TARGET` variables.

Cross-compiling for Android from Linux (unsupported)
....................................................

To build Python with Android NDK set up emulator, toolchain and ABI (see `Android CMake
Guide <https://developer.android.com/ndk/guides/cmake>`_).

.. code:: bash

# Unix
cmake -DCMAKE_INSTALL_PREFIX:PATH=${HOME}/scratch/python-install -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake -DANDROID_ABI=armeabi-v7a -DCMAKE_CROSSCOMPILING_EMULATOR=adb-emu.sh -DANDROID_ALLOW_UNDEFINED_SYMBOLS=On -DENABLE_DECIMAL=Off -DENABLE_CTYPES=Off -DBUILD_EXTENSIONS_AS_BUILTIN=On -DANDROID_PLATFORM=21 ../python-cmake-buildsystem

adb-emu.sh sends executable configuration files and launches them on connected device or launched
emulator. Ensure device or emulator have same architecture you builds python:

.. code:: bash

#!/bin/sh
adb push "$1" /data/local/tmp/ 1>/dev/null 2>/dev/null
if [ $# -eq 1 ]; then
adb shell /data/local/tmp/$(basename $1)
elif [ $# -eq 3 ]; then
adb push "$2" /data/local/tmp/ 1>/dev/null 2>/dev/null
adb shell /data/local/tmp/$(basename $1) /data/local/tmp/$(basename $2) /data/local/tmp/$(basename $3)
adb pull /data/local/tmp/$(basename $3) "$3" 1>/dev/null 2>/dev/null
fi

Licenses
--------

Expand Down
92 changes: 40 additions & 52 deletions cmake/ConfigureChecks.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,12 @@ check_include_files(grp.h HAVE_GRP_H)
check_include_files(ieeefp.h HAVE_IEEEFP_H)
check_include_files(inttypes.h HAVE_INTTYPES_H) # libffi and cpython
check_include_files(io.h HAVE_IO_H)
check_include_files(langinfo.h HAVE_LANGINFO_H)
if (${CMAKE_SYSTEM_NAME} MATCHES "^Android")
set(HAVE_LANGINFO_H 0) # Android cann't link functions from langinfo.h
else()
check_include_files(langinfo.h HAVE_LANGINFO_H)
endif()

check_include_files(libintl.h HAVE_LIBINTL_H)
check_include_files(libutil.h HAVE_LIBUTIL_H)
check_include_files(linux/tipc.h HAVE_LINUX_TIPC_H)
Expand Down Expand Up @@ -436,6 +441,11 @@ if(CMAKE_SYSTEM MATCHES "VxWorks\\-7$")
set(HAVE_LIBUTIL 0)
endif()

if(CMAKE_SYSTEM MATCHES "^Android")
set(LIBUTIL_EXPECTED 0)
set(HAVE_LIBUTIL 0)
endif()

if(LIBUTIL_EXPECTED)
check_function_exists("openpty" HAVE_BUILTIN_OPENPTY)
if(HAVE_BUILTIN_OPENPTY)
Expand Down Expand Up @@ -1084,60 +1094,38 @@ endif()
# Check for various properties of floating point
#
#######################################################################

# Check whether C doubles are little-endian IEEE 754 binary64
set(check_src ${PROJECT_BINARY_DIR}/CMakeFiles/ac_cv_little_endian_double.c)
file(WRITE ${check_src} "#include <string.h>
int main() {
double x = 9006104071832581.0;
if (memcmp(&x, \"\\x05\\x04\\x03\\x02\\x01\\xff\\x3f\\x43\", 8) == 0)
return 0;
else
return 1;
}
")
python_platform_test_run(
DOUBLE_IS_LITTLE_ENDIAN_IEEE754
"Checking whether C doubles are little-endian IEEE 754 binary64"
${check_src}
DIRECT
)

# Check whether C doubles are big-endian IEEE 754 binary64
set(check_src ${PROJECT_BINARY_DIR}/CMakeFiles/ac_cv_big_endian_double.c)
file(WRITE ${check_src} "#include <string.h>
int main() {
double x = 9006104071832581.0;
if (memcmp(&x, \"\\x43\\x3f\\xff\\x01\\x02\\x03\\x04\\x05\", 8) == 0)
return 0;
else
return 1;
}
file(WRITE ${check_src} "
double d = 90904234967036810337470478905505011476211692735615632014797120844053488865816695273723469097858056257517020191247487429516932130503560650002327564517570778480236724525140520121371739201496540132640109977779420565776568942592.0;
")
python_platform_test_run(
DOUBLE_IS_BIG_ENDIAN_IEEE754
"Checking whether C doubles are big-endian IEEE 754 binary64"
${check_src}
DIRECT
)

# Check whether C doubles are ARM mixed-endian IEEE 754 binary64
set(check_src ${PROJECT_BINARY_DIR}/CMakeFiles/ac_cv_mixed_endian_double.c)
file(WRITE ${check_src} "#include <string.h>
int main() {
double x = 9006104071832581.0;
if (memcmp(&x, \"\\x01\\xff\\x3f\\x43\\x05\\x04\\x03\\x02\", 8) == 0)
return 0;
else
return 1;
}
")
python_platform_test_run(
DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754
"Checking doubles are ARM mixed-endian IEEE 754 binary64"
${check_src}
DIRECT
)
# TODO: factorize this try_compile statement
try_compile(DOUBLE_BIG_ENDIAN_TEST_COMPILED
${CMAKE_CURRENT_BINARY_DIR}
${check_src}
COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
"${CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES}"
"${CHECK_C_SOURCE_COMPILES_ADD_INCLUDES}"
COPY_FILE ${CMAKE_CURRENT_BINARY_DIR}/double_big_endian.bin)

if(DOUBLE_BIG_ENDIAN_TEST_COMPILED)
file(READ ${CMAKE_CURRENT_BINARY_DIR}/double_big_endian.bin DOUBLE_BIG_ENDIAN_DATA)
string(FIND ${DOUBLE_BIG_ENDIAN_DATA} "noonsees" NOONSEES)
if(NOONSEES)
set(DOUBLE_IS_BIG_ENDIAN_IEEE754 1)
set(DOUBLE_IS_LITTLE_ENDIAN_IEEE754 0)
else()
string(FIND ${DOUBLE_BIG_ENDIAN_DATA} "seesnoon" SEESNOON)
if(SEESNOON)
set(DOUBLE_IS_BIG_ENDIAN_IEEE754 0)
set(DOUBLE_IS_LITTLE_ENDIAN_IEEE754 1)
else()
message(WARNING "Could not determine if double precision floats endianness")
endif()
endif()
endif()

# The short float repr introduced in Python 3.1 requires the
# correctly-rounded string <-> double conversion functions from
Expand Down
2 changes: 1 addition & 1 deletion cmake/Extensions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ function(add_python_extension name)
)
endif()

if(APPLE)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set_target_properties(${target_name} PROPERTIES
LINK_FLAGS -Wl,-undefined,dynamic_lookup
SUFFIX .so
Expand Down
8 changes: 5 additions & 3 deletions cmake/extensions/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,10 @@ if(PY_VERSION VERSION_GREATER_EQUAL "3.9")
endif()

# UNIX-only extensions
add_python_extension(fcntl REQUIRES UNIX SOURCES fcntlmodule.c)
add_python_extension(grp REQUIRES UNIX SOURCES grpmodule.c)
if(NOT CMAKE_SYSTEM MATCHES Android)
add_python_extension(fcntl REQUIRES UNIX SOURCES fcntlmodule.c)
add_python_extension(grp REQUIRES UNIX SOURCES grpmodule.c)
endif()

set(nis_REQUIRES UNIX HAVE_LIBNSL)
set(nis_LIBRARIES ${HAVE_LIBNSL})
Expand Down Expand Up @@ -500,7 +502,7 @@ elseif(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
elseif(${CMAKE_SIZEOF_VOID_P} EQUAL 4)
if(HAVE_GCC_ASM_FOR_X87 AND
(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
AND NOT CMAKE_SYSTEM MATCHES SunOS
AND NOT CMAKE_SYSTEM MATCHES SunOS AND NOT CMAKE_SYSTEM MATCHES Android
)
# solaris: problems with register allocation.
# icc >= 11.0 works as well.
Expand Down
32 changes: 17 additions & 15 deletions cmake/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,22 @@ endif()

# Generate grammar tables in install directory
# XXX Should a custom target be added to generate file at built time ?
install(CODE "find_program(
PYTHON_EXECUTABLE python
HINTS \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${BIN_INSTALL_DIR}
NO_DEFAULT_PATH)
set(wrapper)
if(UNIX)
set(_envvar LD_LIBRARY_PATH)
if(APPLE)
set(_envvar DYLD_LIBRARY_PATH)
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "^Android")
install(CODE "find_program(
PYTHON_EXECUTABLE python
HINTS \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${BIN_INSTALL_DIR}
NO_DEFAULT_PATH)
set(wrapper)
if(UNIX)
set(_envvar LD_LIBRARY_PATH)
if(APPLE)
set(_envvar DYLD_LIBRARY_PATH)
endif()
set(wrapper env \${_envvar}=\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${LIBPYTHON_LIBDIR})
endif()
set(wrapper env \${_envvar}=\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${LIBPYTHON_LIBDIR})
execute_process(COMMAND \${wrapper} \${PYTHON_EXECUTABLE} -m lib2to3.pgen2.driver
\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${PYTHONHOME}/lib2to3/Grammar.txt)
execute_process(COMMAND \${wrapper} \${PYTHON_EXECUTABLE} -m lib2to3.pgen2.driver
\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${PYTHONHOME}/lib2to3/PatternGrammar.txt)
")
endif()
execute_process(COMMAND \${wrapper} \${PYTHON_EXECUTABLE} -m lib2to3.pgen2.driver
\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${PYTHONHOME}/lib2to3/Grammar.txt)
execute_process(COMMAND \${wrapper} \${PYTHON_EXECUTABLE} -m lib2to3.pgen2.driver
\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${PYTHONHOME}/lib2to3/PatternGrammar.txt)
")
16 changes: 16 additions & 0 deletions cmake/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,28 @@ char *PLATFORM_TRIPLET =

#if defined(__linux__)
# if defined(__x86_64__) && defined(__LP64__)
# if defined(__ANDROID_NDK__)
"x86_64-linux-android"
# else
"x86_64-linux-gnu"
# endif
# elif defined(__x86_64__) && defined(__ILP32__)
"x86_64-linux-gnux32"
# elif defined(__i386__)
# if defined(__ANDROID_NDK__)
"i686-linux-android"
# else
"i386-linux-gnu"
# endif
# elif defined(__aarch64__) && defined(__AARCH64EL__)
# if defined(__ILP32__)
"aarch64_ilp32-linux-gnu"
# else
# if defined(__ANDROID_NDK__)
"aarch64-linux-android"
# else
"aarch64-linux-gnu"
# endif
# endif
# elif defined(__aarch64__) && defined(__AARCH64EB__)
# if defined(__ILP32__)
Expand All @@ -45,7 +57,11 @@ char *PLATFORM_TRIPLET =
# endif
# elif defined(__ARM_EABI__) && !defined(__ARM_PCS_VFP)
# if defined(__ARMEL__)
# if defined(__ANDROID_NDK__)
"arm-linux-androideabi"
# else
"arm-linux-gnueabi"
# endif
# else
"armeb-linux-gnueabi"
# endif
Expand Down
2 changes: 1 addition & 1 deletion cmake/python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ if(WIN32)
)
endif()

if(UNIX AND PY_VERSION VERSION_GREATER "2.7.4")
if(UNIX AND PY_VERSION VERSION_GREATER "2.7.4" AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "^Android")
# Setup landmark allowing to run the interpreter from a build tree. See 'getpath.c' for details.
set(_sysconfigdata_py "_sysconfigdata.py")
if("${PY_VERSION}" VERSION_GREATER_EQUAL "3.6.0")
Expand Down