Skip to content
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

gh-116622: Fix testPyObjectPrintOSError on Android #122487

Merged
merged 3 commits into from
Jul 31, 2024
Merged
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
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
Expand All @@ -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(
Expand Down Expand Up @@ -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):
Expand All @@ -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,
Expand Down
9 changes: 8 additions & 1 deletion Android/testbed/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
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
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
Loading