dist: Android fixes, esp. for Python 3.13

This changes the use of sys.executable to sys.platlibdir, which requires Python 3.9+ (but that's probably okay since Python 3.8 is EOL)

Python 3.13 has proper official Android support, including built-in stdout/stderr redirection, but it only does so if sys.executable is not set
This commit is contained in:
rdb 2024-11-27 00:10:37 +01:00
parent 46e90058b9
commit d6acaaffb0
3 changed files with 47 additions and 26 deletions

View File

@ -925,7 +925,22 @@ class Freezer:
if sys.version_info < (3, 8):
abi_flags += 'm'
if 'linux' in self.platform:
if 'android' in self.platform:
arch = self.platform.split('_', 1)[1]
if arch in ('arm64', 'aarch64'):
suffixes.append(('.cpython-{0}{1}-aarch64-linux-android.so'.format(abi_version, abi_flags), 'rb', 3))
elif arch in ('arm', 'armv7l'):
suffixes.append(('.cpython-{0}{1}-arm-linux-androideabi.so'.format(abi_version, abi_flags), 'rb', 3))
elif arch in ('x86_64', 'amd64'):
suffixes.append(('.cpython-{0}{1}-x86_64-linux-android.so'.format(abi_version, abi_flags), 'rb', 3))
elif arch in ('i386', 'i686'):
suffixes.append(('.cpython-{0}{1}-i686-linux-android.so'.format(abi_version, abi_flags), 'rb', 3))
suffixes += [
('.abi{0}.so'.format(sys.version_info[0]), 'rb', 3),
('.so', 'rb', 3),
]
elif 'linux' in self.platform:
suffixes += [
('.cpython-{0}{1}-x86_64-linux-gnu.so'.format(abi_version, abi_flags), 'rb', 3),
('.cpython-{0}{1}-i686-linux-gnu.so'.format(abi_version, abi_flags), 'rb', 3),
@ -1150,6 +1165,9 @@ class Freezer:
self.modules['_frozen_importlib'] = self.ModuleDef('importlib._bootstrap', implicit = True)
self.modules['_frozen_importlib_external'] = self.ModuleDef('importlib._bootstrap_external', implicit = True)
if self.platform.startswith('android'):
self.modules['_android_support'] = self.ModuleDef('_android_support', implicit = True)
for moduleName in startupModules:
if moduleName not in self.modules:
self.addModule(moduleName, implicit = True)

View File

@ -188,11 +188,26 @@ FrozenImporter.get_data = get_data
"""
SITE_PY_ANDROID = """
# Define this first, before we import anything that might import an extension
# module.
import sys, os
from importlib import _bootstrap, _bootstrap_external
class AndroidExtensionFinder:
@classmethod
def find_spec(cls, fullname, path=None, target=None):
soname = 'libpy.' + fullname + '.so'
path = os.path.join(sys.platlibdir, soname)
if os.path.exists(path):
loader = _bootstrap_external.ExtensionFileLoader(fullname, path)
return _bootstrap.ModuleSpec(fullname, loader, origin=path)
sys.meta_path.append(AndroidExtensionFinder)
from _frozen_importlib import _imp, FrozenImporter
from importlib import _bootstrap_external
from importlib.abc import Loader, MetaPathFinder
from importlib.machinery import ModuleSpec
from io import RawIOBase, TextIOWrapper
from android_log import write as android_log_write
@ -242,8 +257,9 @@ class AndroidLogStream:
def writable(self):
return True
sys.stdout = AndroidLogStream(2, 'Python')
sys.stderr = AndroidLogStream(3, 'Python')
if sys.version_info < (3, 13):
sys.stdout = AndroidLogStream(4, 'python.stdout')
sys.stderr = AndroidLogStream(5, 'python.stderr')
# Alter FrozenImporter to give a __file__ property to frozen modules.
@ -262,20 +278,6 @@ def get_data(path):
FrozenImporter.find_spec = find_spec
FrozenImporter.get_data = get_data
class AndroidExtensionFinder(MetaPathFinder):
@classmethod
def find_spec(cls, fullname, path=None, target=None):
soname = 'libpy.' + fullname + '.so'
path = os.path.join(os.path.dirname(sys.executable), soname)
if os.path.exists(path):
loader = _bootstrap_external.ExtensionFileLoader(fullname, path)
return ModuleSpec(fullname, loader, origin=path)
sys.meta_path.append(AndroidExtensionFinder)
"""

View File

@ -161,8 +161,6 @@ void android_main(struct android_app *app) {
std::string dtool_name = std::string(libdir) + "/libp3dtool.so";
ExecutionEnvironment::set_dtool_name(dtool_name);
android_cat.info() << "Path to dtool: " << dtool_name << "\n";
env->ReleaseStringUTFChars(libdir_jstr, libdir);
}
// Get the path to the APK.
@ -184,6 +182,7 @@ void android_main(struct android_app *app) {
// Map the blob to memory
void *blob = map_blob(lib_path, (off_t)blobinfo.blob_offset, (size_t)blobinfo.blob_size);
env->ReleaseStringUTFChars(lib_path_jstr, lib_path);
assert(blob != NULL);
assert(blobinfo.num_pointers <= MAX_NUM_POINTERS);
@ -242,14 +241,16 @@ void android_main(struct android_app *app) {
preconfig.utf8_mode = 1;
PyStatus status = Py_PreInitialize(&preconfig);
if (PyStatus_Exception(status)) {
Py_ExitStatusException(status);
return;
env->ReleaseStringUTFChars(libdir_jstr, libdir);
Py_ExitStatusException(status);
return;
}
// Register the android_log module.
if (PyImport_AppendInittab("android_log", &PyInit_android_log) < 0) {
android_cat.error()
<< "Failed to register android_log module.\n";
env->ReleaseStringUTFChars(libdir_jstr, libdir);
return;
}
@ -259,8 +260,8 @@ void android_main(struct android_app *app) {
config.buffered_stdio = 0;
config.configure_c_stdio = 0;
config.write_bytecode = 0;
PyConfig_SetBytesString(&config, &config.executable, lib_path);
env->ReleaseStringUTFChars(lib_path_jstr, lib_path);
PyConfig_SetBytesString(&config, &config.platlibdir, libdir);
env->ReleaseStringUTFChars(libdir_jstr, libdir);
status = Py_InitializeFromConfig(&config);
PyConfig_Clear(&config);