Skip to content
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
69 changes: 69 additions & 0 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,79 @@ jobs:
CC: ${{ matrix.c-compiler }}
CXX: ${{ matrix.cxx-compiler }}

tests-android:
runs-on: ${{ matrix.host }}
strategy:
matrix:
ndk-arch: [x86_64, arm64-v8a, x86, armeabi-v7a]
host: [ubuntu-24.04]
python-version: [3.8.20, 3.9.22, 3.10.17, 3.11.12]
name: python-android-${{ matrix.ndk-arch }}-${{ matrix.python-version }}-${{ matrix.host }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
path: src
- name: Enable KVM
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: Make build and prefix directories
run: |
mkdir build
mkdir install-prefix
mkdir bootstrap-build
mkdir bootstrap-install-prefix
- name: Check for bootstrap needed
id: check-bootstrap
shell: cmake -P {0}
run: |
string(REPLACE "." ";" VERSION_LIST "${{ matrix.python-version }}")
list(GET VERSION_LIST 0 PY_VERSION_MAJOR)
list(GET VERSION_LIST 1 PY_VERSION_MINOR)
list(GET VERSION_LIST 2 PY_VERSION_PATCH)
set(PY_VERSION "${PY_VERSION_MAJOR}.${PY_VERSION_MINOR}.${PY_VERSION_PATCH}")
if(PY_VERSION VERSION_GREATER_EQUAL "3.11")
file(APPEND "$ENV{GITHUB_OUTPUT}" "needed=yes")
endif()
- name: Bootstrap
if: steps.check-bootstrap.outputs.needed == 'yes'
run: |
cd bootstrap-build
cmake -DCMAKE_INSTALL_PREFIX:PATH=../bootstrap-install-prefix -DPYTHON_VERSION=${{ matrix.python-version }} $(pwd)/../src/
cmake --build . -- VERBOSE=1
cmake --build . --target install
- name: run action
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: ${{ startsWith(matrix.ndk-arch, 'x86') && 21 || 30 }}
target: ${{ startsWith(matrix.ndk-arch, 'x86') && 'default' || 'google_apis' }}
arch: ${{ matrix.ndk-arch == 'x86' && 'x86' || 'x86_64' }}
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: build/
ndk: 23.0.7421159
channel: beta
script: |
adb devices
cmake -DANDROID_NDK=/usr/local/lib/android/sdk/ndk/23.0.7421159/ -DCMAKE_INSTALL_PREFIX:PATH=../install-prefix -DCMAKE_TOOLCHAIN_FILE=/usr/local/lib/android/sdk/ndk/23.0.7421159/build/cmake/android.toolchain.cmake -DANDROID_ABI=${{ matrix.ndk-arch }} -DCMAKE_CROSSCOMPILING_EMULATOR=$(pwd)/../src/.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 -DPYTHON_VERSION=${{ matrix.python-version }} -DBUILD_PYTHON=../bootstrap-install-prefix/bin/python $(pwd)/../src/
cmake --build . -- VERBOSE=1
cmake --build . --target install


pass: # This job does nothing and is only used for the branch protection
if: always()
needs:
- tests
- tests-android

runs-on: ubuntu-latest

Expand Down
17 changes: 17 additions & 0 deletions .github/workflows/adb-emu.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/sh
adb push "$1" /data/local/tmp/ 1>/dev/null 2>/dev/null
BINARY=$(basename "$1")
if [ $# -eq 1 ]; then
adb shell "/data/local/tmp/${BINARY}"
elif [ $# -eq 3 ]; then
adb push "$2" /data/local/tmp/ 1>/dev/null 2>/dev/null
adb shell "/data/local/tmp/${BINARY}" "/data/local/tmp/$(basename $2)" "/data/local/tmp/$(basename $3)"
adb pull "/data/local/tmp/$(basename $3)" "$3" 1>/dev/null 2>/dev/null
elif [ $# -eq 4 ] && [ "${BINARY}" = "_freeze_importlib" ]; then
adb push "$3" /data/local/tmp/ 1>/dev/null 2>/dev/null
adb shell "/data/local/tmp/${BINARY}" "$2" "/data/local/tmp/$(basename $3)" "/data/local/tmp/$(basename $4)"
adb pull "/data/local/tmp/$(basename $4)" "$4" 1>/dev/null 2>/dev/null
else
echo "Unknown number of arguments $# for ${BINARY}"
exit 1
fi
24 changes: 23 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,28 @@ else()
set(WITH_STATIC_DEPENDENCIES 0)
endif()

if(ANDROID AND PY_VERSION VERSION_GREATER_EQUAL "3.11")
set(BUILD_PYTHON "" CACHE PATH "path to build ``python`` binary for cross compiling")
if(NOT BUILD_PYTHON)
message(FATAL_ERROR "Cross compiling requires -DBUILD_PYTHON=<PATH>")
endif()
if(NOT EXISTS ${BUILD_PYTHON})
message(FATAL_ERROR "invalid or missing build python binary ${BUILD_PYTHON}")
endif()
execute_process(
COMMAND ${BUILD_PYTHON} -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"
OUTPUT_VARIABLE BUILD_PYTHON_VER
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE BUILD_PYTHON_EXEC_RESULT
)
if(NOT BUILD_PYTHON_EXEC_RESULT EQUAL 0)
message(FATAL_ERROR "can not execute build python binary ${BUILD_PYTHON}")
endif()
if(NOT "${BUILD_PYTHON_VER}" STREQUAL "${PY_VERSION_MAJOR}.${PY_VERSION_MINOR}")
message(FATAL_ERROR "\"${BUILD_PYTHON}\" has incompatible version ${BUILD_PYTHON_VER} (expected: ${PY_VERSION_MAJOR}.${PY_VERSION_MINOR})")
endif()
endif()

# Detect source directory
set(_landmark "pyconfig.h.in") # CMake will look for this file.
if(NOT (SRC_DIR AND EXISTS ${SRC_DIR}/${_landmark}))
Expand Down Expand Up @@ -799,7 +821,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
88 changes: 35 additions & 53 deletions cmake/ConfigureChecks.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,11 @@ 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 @@ -532,7 +536,7 @@ find_library(HAVE_LIBTERMCAP termcap)
set(LIBUTIL_LIBRARIES )
set(LIBUTIL_EXPECTED 1)

if(CMAKE_SYSTEM MATCHES "VxWorks\\-7$")
if(ANDROID OR CMAKE_SYSTEM MATCHES "VxWorks\\-7$")
set(LIBUTIL_EXPECTED 0)
set(HAVE_LIBUTIL 0)
endif()
Expand Down Expand Up @@ -1298,60 +1302,38 @@ python_platform_test(
# 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(APPLE OR ANDROID)
set_target_properties(${target_name} PROPERTIES
LINK_FLAGS -Wl,-undefined,dynamic_lookup
SUFFIX .so
Expand Down
31 changes: 18 additions & 13 deletions cmake/extensions/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -373,16 +373,18 @@ add_python_extension(_xxtestfuzz
_xxtestfuzz/fuzzer.c
)

# Python 3.8
set(_wide_char_modifier "L")
add_python_extension(_testinternalcapi
REQUIRES
IS_PY3_8_OR_GREATER
SOURCES
_testinternalcapi.c
DEFINITIONS
"PY3_DLLNAME=${_wide_char_modifier}\"python3$<$<CONFIG:Debug>:_d>\""
)
if (NOT ANDROID)
# Python 3.8
set(_wide_char_modifier "L")
add_python_extension(_testinternalcapi
REQUIRES
IS_PY3_8_OR_GREATER
SOURCES
_testinternalcapi.c
DEFINITIONS
"PY3_DLLNAME=${_wide_char_modifier}\"python3$<$<CONFIG:Debug>:_d>\""
)
endif()

# Python 3.9
add_python_extension(_peg_parser ALWAYS_BUILTIN
Expand Down Expand Up @@ -417,9 +419,11 @@ add_python_extension(_xxsubinterpreters ${WIN32_BUILTIN}
_xxsubinterpretersmodule.c
)

# UNIX-only extensions
add_python_extension(fcntl REQUIRES UNIX SOURCES fcntlmodule.c)
add_python_extension(grp REQUIRES UNIX SOURCES grpmodule.c)
if(NOT ANDROID)
# UNIX-only extensions
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 @@ -834,6 +838,7 @@ 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 ANDROID
)
# solaris: problems with register allocation.
# icc >= 11.0 works as well.
Expand Down
34 changes: 18 additions & 16 deletions cmake/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,22 @@ endforeach()

# 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)
endif()
set(wrapper env \${_envvar}=\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${LIBPYTHON_LIBDIR})
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()
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)
")
4 changes: 3 additions & 1 deletion cmake/libpython/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,7 @@ set(LIBPYTHON_DEEPFREEZE_SOURCES )

if(PY_VERSION VERSION_GREATER_EQUAL "3.11")

if(NOT ANDROID)
# Build _bootstrap_python executable
add_executable(_bootstrap_python
${SRC_DIR}/Programs/_bootstrap_python.c
Expand All @@ -763,6 +764,7 @@ target_compile_definitions(_bootstrap_python
PUBLIC
Py_NO_ENABLE_SHARED
)
endif()

list(APPEND LIBPYTHON_DEEPFREEZE_SOURCES
${SRC_DIR}/Python/deepfreeze/deepfreeze.c
Expand All @@ -773,7 +775,7 @@ set(DEEPFREEZE_PY ${SRC_DIR}/Tools/$<IF:$<VERSION_GREATER_EQUAL:${PY_VERSION},3.
add_custom_command(
OUTPUT ${LIBPYTHON_DEEPFREEZE_SOURCES}
COMMAND
_bootstrap_python
$<IF:$<BOOL:${ANDROID}>,${BUILD_PYTHON},_bootstrap_python>
${DEEPFREEZE_PY}
"${SRC_DIR}/Python/frozen_modules/importlib._bootstrap.h:importlib._bootstrap"
"${SRC_DIR}/Python/frozen_modules/importlib._bootstrap_external.h:importlib._bootstrap_external"
Expand Down
Loading
Loading