Skip to content

gh-116622: Fix testPyObjectPrintOSError on Android #122487

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

Merged
merged 3 commits into from
Jul 31, 2024
Merged
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
25 changes: 19 additions & 6 deletions Android/android.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python3

import argparse
from glob import glob
import os
import re
import shutil
@@ -16,16 +17,21 @@
CROSS_BUILD_DIR = CHECKOUT / "cross-build"


def delete_if_exists(path):
if path.exists():
def delete_glob(pattern):
# Path.glob doesn't accept non-relative patterns.
for path in glob(str(pattern)):
path = Path(path)
print(f"Deleting {path} ...")
shutil.rmtree(path)
if path.is_dir() and not path.is_symlink():
shutil.rmtree(path)
else:
path.unlink()


def subdir(name, *, clean=None):
path = CROSS_BUILD_DIR / name
if clean:
delete_if_exists(path)
delete_glob(path)
if not path.exists():
if clean is None:
sys.exit(
@@ -150,10 +156,17 @@ def configure_host_python(context):


def make_host_python(context):
# The CFLAGS and LDFLAGS set in android-env include the prefix dir, so
# delete any previously-installed Python libs and include files to prevent
# them being used during the build.
host_dir = subdir(context.host)
prefix_dir = host_dir / "prefix"
delete_glob(f"{prefix_dir}/include/python*")
delete_glob(f"{prefix_dir}/lib/libpython*")

os.chdir(host_dir / "build")
run(["make", "-j", str(os.cpu_count())], host=context.host)
run(["make", "install", f"prefix={host_dir}/prefix"], host=context.host)
run(["make", "install", f"prefix={prefix_dir}"], host=context.host)


def build_all(context):
@@ -164,7 +177,7 @@ def build_all(context):


def clean_all(context):
delete_if_exists(CROSS_BUILD_DIR)
delete_glob(CROSS_BUILD_DIR)


# To avoid distributing compiled artifacts without corresponding source code,
9 changes: 8 additions & 1 deletion Android/testbed/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -7,10 +7,17 @@ plugins {

val PYTHON_DIR = File(projectDir, "../../..").canonicalPath
val PYTHON_CROSS_DIR = "$PYTHON_DIR/cross-build"

val ABIS = mapOf(
"arm64-v8a" to "aarch64-linux-android",
"x86_64" to "x86_64-linux-android",
)
).filter { File("$PYTHON_CROSS_DIR/${it.value}").exists() }
if (ABIS.isEmpty()) {
throw GradleException(
"No Android ABIs found in $PYTHON_CROSS_DIR: see Android/README.md " +
"for building instructions."
)
}

val PYTHON_VERSION = File("$PYTHON_DIR/Include/patchlevel.h").useLines {
for (line in it) {
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Make :any:`PyObject_Print` work around a bug in Android and OpenBSD which
prevented it from throwing an exception when trying to write to a read-only
stream.
11 changes: 9 additions & 2 deletions Objects/object.c
Original file line number Diff line number Diff line change
@@ -536,6 +536,7 @@ int
PyObject_Print(PyObject *op, FILE *fp, int flags)
{
int ret = 0;
int write_error = 0;
if (PyErr_CheckSignals())
return -1;
#ifdef USE_STACKCHECK
@@ -574,14 +575,20 @@ PyObject_Print(PyObject *op, FILE *fp, int flags)
ret = -1;
}
else {
fwrite(t, 1, len, fp);
/* Versions of Android and OpenBSD from before 2023 fail to
set the `ferror` indicator when writing to a read-only
stream, so we need to check the return value.
(https://github.com/openbsd/src/commit/fc99cf9338942ecd9adc94ea08bf6188f0428c15) */
if (fwrite(t, 1, len, fp) != (size_t)len) {
write_error = 1;
}
}
Py_DECREF(s);
}
}
}
if (ret == 0) {
if (ferror(fp)) {
if (write_error || ferror(fp)) {
PyErr_SetFromErrno(PyExc_OSError);
clearerr(fp);
ret = -1;