Skip to content

Android #323

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

Closed
wants to merge 4 commits into from
Closed
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
6 changes: 3 additions & 3 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ jobs:

name: python-${{ matrix.python-version }}-${{ matrix.runs-on }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
with:
fetch-depth: 0
path: src

- name: Setup cmake
uses: jwlawson/actions-setup-cmake@v1.13.1
uses: jwlawson/actions-setup-cmake@v1.9
with:
cmake-version: 3.13.5

Expand All @@ -43,7 +43,7 @@ jobs:
sudo xcode-select -s "/Applications/Xcode_11.7.app"

- name: Download dashboard script
uses: actions/checkout@v3
uses: actions/checkout@v2
with:
repository: 'python-cmake-buildsystem/python-cmake-buildsystem'
ref: dashboard
Expand Down
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(APPLE OR ANDROID)
set(MAKEFILE_LDSHARED_FLAGS "-dynamiclib -headerpad_max_install_names -undefined dynamic_lookup")
endif()
configure_file(cmake/makefile-variables.in
Expand Down
27 changes: 27 additions & 0 deletions CROSS-COMPILING.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Cross-compiling
===============

Android target from Linux host
..............................

*This is is under active development. Its content, API and behavior may change at any time. We mean it!*

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=../python-cmake-buildsystem/run_on_android.sh \
-DANDROID_ALLOW_UNDEFINED_SYMBOLS=ON \
-DENABLE_DECIMAL=OFF \
-DENABLE_CTYPES=OFF \
-DANDROID_PLATFORM=21 \
../python-cmake-buildsystem

``run_on_android.sh`` sends executable configuration files and launches them on connected device or launched
emulator. Ensure device or emulator have same architecture you builds python.
110 changes: 50 additions & 60 deletions cmake/ConfigureChecks.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -204,11 +204,16 @@ endif()
message(STATUS "${_msg} - ${ABIFLAGS}")

set(_msg "Checking SOABI")
try_run(PLATFORM_RUN PLATFORM_COMPILE
${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/cmake/platform.c
RUN_OUTPUT_VARIABLE PLATFORM_TRIPLET)
if(NOT PLATFORM_COMPILE)
message(FATAL_ERROR "We could not determine the platform. Please clean the ${CMAKE_PROJECT_NAME} environment and try again...")
set(PLATFORM_TRIPLET )
if (ANDROID)
set(PLATFORM_TRIPLET "${CMAKE_ANDROID_ARCH_ABI}-linux-android")
else()
try_run(PLATFORM_RUN PLATFORM_COMPILE
${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/cmake/platform.c
RUN_OUTPUT_VARIABLE PLATFORM_TRIPLET)
if(NOT PLATFORM_COMPILE)
message(FATAL_ERROR "We could not determine the platform. Please clean the ${CMAKE_PROJECT_NAME} environment and try again...")
endif()
endif()
set(SOABI "cpython-${PY_VERSION_MAJOR}${PY_VERSION_MINOR}${ABIFLAGS}-${PLATFORM_TRIPLET}")

Expand Down Expand Up @@ -270,7 +275,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 (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 @@ -431,7 +441,7 @@ find_library(HAVE_LIBTERMCAP termcap)
set(LIBUTIL_LIBRARIES )
set(LIBUTIL_EXPECTED 1)

if(CMAKE_SYSTEM MATCHES "VxWorks\\-7$")
if((CMAKE_SYSTEM MATCHES "VxWorks\\-7$") OR ANDROID)
set(LIBUTIL_EXPECTED 0)
set(HAVE_LIBUTIL 0)
endif()
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 Expand Up @@ -1286,8 +1274,9 @@ check_c_source_compiles("
int main() {int a = MAP_ANONYMOUS;}"
HAVE_MMAP_ANON)

# libffi specific: Check for /dev/zero support for anonymous memory maps
check_c_source_runs("
# libffi specific: Check for /dev/zero support as a fallback for anonymous memory maps
if(NOT HAVE_MMAP_ANON)
check_c_source_runs("
#include <stdlib.h>
#include <sys/types.h>
#include <sys/mman.h>
Expand All @@ -1305,6 +1294,7 @@ int main(void) {
}
exit(0);
}" HAVE_MMAP_DEV_ZERO)
endif()

if(IS_PY3)

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(APPLE OR ANDROID)
set_target_properties(${target_name} PROPERTIES
LINK_FLAGS -Wl,-undefined,dynamic_lookup
SUFFIX .so
Expand Down
4 changes: 3 additions & 1 deletion cmake/extensions/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,7 @@ endif()

if(ENABLE_DECIMAL)
message(STATUS "extension_decimal: libmpdec_config [${libmpdec_config}]")
endif()

add_python_extension(_decimal
SOURCES
_decimal/_decimal.c
Expand All @@ -562,6 +562,8 @@ endif()

endif()

endif()

# Build expat using the system expat if it's installed, otherwise use the
# builtin version.
if(EXPAT_LIBRARIES AND EXPAT_INCLUDE_DIRS)
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 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)
")
7 changes: 6 additions & 1 deletion cmake/libpython/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ if(WIN32 AND IS_PY3)
endif()

set(LIBPYTHON_FROZEN_SOURCES )
if(IS_PY3)
if(IS_PY3 AND NOT CMAKE_CROSSCOMPILING)

# Build _freeze_importlib executable
add_executable(_freeze_importlib
Expand Down Expand Up @@ -512,6 +512,11 @@ endif()
# the frozen sources.
add_custom_target(freeze_modules DEPENDS ${LIBPYTHON_FROZEN_SOURCES})

elseif(IS_PY3 AND CMAKE_CROSSCOMPILING)

# KLUDGE: suppose importlib.h and importlib_external.h are already present.
add_custom_target(freeze_modules)

endif()

if(PY_VERSION VERSION_LESS "3.8")
Expand Down
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 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
9 changes: 9 additions & 0 deletions run_on_android.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