From d9189e84c8fbf07c6f0fe34b7a534f896e23b7cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Biernacki?= Date: Thu, 30 Oct 2025 17:40:32 +0100 Subject: [PATCH 1/3] Keep a way to build with PYO3_NO_PYTHON --- server/pypi/README.md | 3 ++- server/pypi/build-wheel.py | 23 +++++++++++---------- server/pypi/packages/cryptography/meta.yaml | 4 ++++ 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/server/pypi/README.md b/server/pypi/README.md index 184f440d0b..3bbdef2752 100644 --- a/server/pypi/README.md +++ b/server/pypi/README.md @@ -63,7 +63,8 @@ these can be installed using your distribution. Some of them have special entrie [here](https://github.com/mzakharo/android-gfortran/releases/tag/r21e). Create a `fortran` subdirectory in the same directory as this README, and unpack the .bz2 files into it. -* `rust`: `rustup` must be on the PATH. +* `rust`: `rustup` must be on the PATH. One can set `PYO3_NO_PYTHON=1` in `script_env:` to build without a Python interpreter (https://pyo3.rs/main/building-and-distribution#building-abi3-extensions-without-a-python-interpreter). + Building with a Python interpreter is supported only for Python 3.13 and above. ## Building a package diff --git a/server/pypi/build-wheel.py b/server/pypi/build-wheel.py index 02d198700f..878582cf8e 100755 --- a/server/pypi/build-wheel.py +++ b/server/pypi/build-wheel.py @@ -664,18 +664,18 @@ def get_rust_env_vars(self, env): env.update({ "RUSTFLAGS": f"-C linker={env['CC']} -L native={self.host_env}/chaquopy/lib", "CARGO_BUILD_TARGET": tool_prefix, - - # Normally PyO3 requires sysconfig modules, which are not currently - # available in the `target` packages for Python 3.12 and older. However, - # since PyO3 0.16.4, it's possible to compile abi3 modules without sysconfig - # modules. This only requires packages to specify the minimum python - # compatibility version via one of the "abi3-py*" features (e.g. - # abi3-py310). Doing this requires the "-L native" flag in RUSTFLAGS above. - # https://pyo3.rs/main/building-and-distribution#building-abi3-extensions-without-a-python-interpreter - "PYO3_NO_PYTHON": "1", "PYO3_CROSS": "1", "PYO3_CROSS_PYTHON_VERSION": self.python, }) + # Normally PyO3 requires sysconfig modules, which are not currently + # available in the `target` packages for Python 3.12 and older, but are available on Python 3.13. + # However, since PyO3 0.16.4, it's possible to compile abi3 modules without sysconfig + # modules. This only requires packages to specify the minimum python + # compatibility version via one of the "abi3-py*" features (e.g. + # abi3-py310). Doing this requires the "-L native" flag in RUSTFLAGS above. + # https://pyo3.rs/main/building-and-distribution#building-abi3-extensions-without-a-python-interpreter + if 'PYO3_NO_PYTHON' not in env: + env["PYO3_CROSS_LIB_DIR"] = self.chaquopy_dir @contextmanager def env_vars(self): @@ -691,8 +691,6 @@ def env_vars(self): if self.needs_python: self.get_python_env_vars(env, pypi_env) - if "rust" in self.non_python_build_reqs: - self.get_rust_env_vars(env) env.update({ # TODO: make everything use HOST instead, and remove this. @@ -712,6 +710,9 @@ def env_vars(self): key, value = var.split("=", 1) env[key] = value + if "rust" in self.non_python_build_reqs: + self.get_rust_env_vars(env) + # We do this unconditionally, because we don't know whether the package requires # CMake (it may be listed in the pyproject.toml build-system requires). self.generate_cmake_toolchain(env) diff --git a/server/pypi/packages/cryptography/meta.yaml b/server/pypi/packages/cryptography/meta.yaml index 09e89d5a17..d626cd9d0b 100644 --- a/server/pypi/packages/cryptography/meta.yaml +++ b/server/pypi/packages/cryptography/meta.yaml @@ -2,6 +2,10 @@ package: name: cryptography version: "42.0.8" +build: + script_env: + - PYO3_NO_PYTHON=1 + requirements: build: - rust From 544da53565b9bff00b27af92b8bc9a0f16aeecb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Biernacki?= Date: Thu, 30 Oct 2025 17:17:19 +0100 Subject: [PATCH 2/3] Recipe to build pydantic-core (required for Pydantic 2) --- server/pypi/build-wheel.py | 40 ++++++++++++-------- server/pypi/packages/pydantic-core/meta.yaml | 9 +++++ 2 files changed, 34 insertions(+), 15 deletions(-) create mode 100644 server/pypi/packages/pydantic-core/meta.yaml diff --git a/server/pypi/build-wheel.py b/server/pypi/build-wheel.py index 878582cf8e..65ee00e2d9 100755 --- a/server/pypi/build-wheel.py +++ b/server/pypi/build-wheel.py @@ -135,6 +135,7 @@ def unpack_and_build(self): self.src_dir = f"{self.build_dir}/src" self.build_env = f"{self.build_dir}/env" self.host_env = f"{self.build_dir}/requirements" + self.chaquopy_dir = f"{self.host_env}/chaquopy" if self.no_unpack: log("Reusing existing build directory due to --no-unpack") @@ -249,6 +250,10 @@ def version_key(ver): if len(zips) != 1: raise CommandError(f"Found {len(zips)} {self.abi} ZIPs in {target_version_dir}") self.target_zip = zips[0] + zips = glob(f"{target_version_dir}/target-*-stdlib.zip") + if len(zips) != 1: + raise CommandError(f"Found {len(zips)} stdlib ZIPs in {target_version_dir}") + self.std_lib_zip = zips[0] def create_build_env(self): python_ver = self.python or ".".join(map(str, sys.version_info[:2])) @@ -507,9 +512,11 @@ def create_dummy_libs(self): for name in ["pthread", "rt"]: run(f"{os.environ['AR']} rc {self.host_env}/chaquopy/lib/lib{name}.a") + def extract_stdlib(self): + run(f"unzip -q -d {self.chaquopy_dir}/lib {self.std_lib_zip}") + def extract_target(self): - chaquopy_dir = f"{self.host_env}/chaquopy" - run(f"unzip -q -d {chaquopy_dir} {self.target_zip} include/* jniLibs/*") + run(f"unzip -q -d {self.chaquopy_dir} {self.target_zip} include/* jniLibs/*") # Only include OpenSSL and SQLite in the environment if the recipe requests # them. This affects grpcio, which provides its own copy of BoringSSL, and gets @@ -522,7 +529,7 @@ def extract_target(self): self.meta["requirements"]["host"].remove(name) except ValueError: for pattern in [f"include/{includes}", f"jniLibs/{self.abi}/{libs}"]: - run(f"rm -r {chaquopy_dir}/{pattern}", shell=True) + run(f"rm -r {self.chaquopy_dir}/{pattern}", shell=True) # When building packages that could be loaded by older versions of Chaquopy, # i.e non-Python packages, and Python packages for 3.12 and older: @@ -538,7 +545,7 @@ def extract_target(self): # # When building only for Python 3.13 and newer, we should use the _python suffix # so our wheels are compatible with any other Python on Android distributions. - lib_dir = f"{chaquopy_dir}/jniLibs/{self.abi}" + lib_dir = f"{self.chaquopy_dir}/jniLibs/{self.abi}" for name in ["crypto", "ssl", "sqlite3"]: python_name = f"lib{name}_python.so" chaquopy_name = f"lib{name}_chaquopy.so" @@ -552,8 +559,10 @@ def extract_target(self): run(f"patchelf --set-soname {chaquopy_name} " f"{lib_dir}/{chaquopy_name}") - run(f"mv {chaquopy_dir}/jniLibs/{self.abi}/* {chaquopy_dir}/lib", shell=True) - run(f"rm -r {chaquopy_dir}/jniLibs") + run(f"mv {self.chaquopy_dir}/jniLibs/{self.abi}/* {self.chaquopy_dir}/lib", shell=True) + run(f"rm -r {self.chaquopy_dir}/jniLibs") + + self.extract_stdlib() def build_with_script(self, build_script): prefix_dir = f"{self.build_dir}/prefix" @@ -664,18 +673,19 @@ def get_rust_env_vars(self, env): env.update({ "RUSTFLAGS": f"-C linker={env['CC']} -L native={self.host_env}/chaquopy/lib", "CARGO_BUILD_TARGET": tool_prefix, + + # Normally PyO3 requires sysconfig modules, which are not currently + # available in the `target` packages for Python 3.12 and older. However, + # since PyO3 0.16.4, it's possible to compile abi3 modules without sysconfig + # modules. This only requires packages to specify the minimum python + # compatibility version via one of the "abi3-py*" features (e.g. + # abi3-py310). Doing this requires the "-L native" flag in RUSTFLAGS above. + # https://pyo3.rs/main/building-and-distribution#building-abi3-extensions-without-a-python-interpreter + # "PYO3_NO_PYTHON": "1", + "PYO3_CROSS_LIB_DIR": self.chaquopy_dir, "PYO3_CROSS": "1", "PYO3_CROSS_PYTHON_VERSION": self.python, }) - # Normally PyO3 requires sysconfig modules, which are not currently - # available in the `target` packages for Python 3.12 and older, but are available on Python 3.13. - # However, since PyO3 0.16.4, it's possible to compile abi3 modules without sysconfig - # modules. This only requires packages to specify the minimum python - # compatibility version via one of the "abi3-py*" features (e.g. - # abi3-py310). Doing this requires the "-L native" flag in RUSTFLAGS above. - # https://pyo3.rs/main/building-and-distribution#building-abi3-extensions-without-a-python-interpreter - if 'PYO3_NO_PYTHON' not in env: - env["PYO3_CROSS_LIB_DIR"] = self.chaquopy_dir @contextmanager def env_vars(self): diff --git a/server/pypi/packages/pydantic-core/meta.yaml b/server/pypi/packages/pydantic-core/meta.yaml new file mode 100644 index 0000000000..4eb21d93b2 --- /dev/null +++ b/server/pypi/packages/pydantic-core/meta.yaml @@ -0,0 +1,9 @@ +package: + name: pydantic-core + version: "2.41.4" + +requirements: + build: + - rust + host: + - python From 9665867c34ab1c09e89cb25fe1f870f56e90f129 Mon Sep 17 00:00:00 2001 From: Herklos Date: Fri, 28 Nov 2025 10:19:30 +0100 Subject: [PATCH 3/3] Bump pydantic core to the latest version --- server/pypi/packages/pydantic-core/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/pypi/packages/pydantic-core/meta.yaml b/server/pypi/packages/pydantic-core/meta.yaml index 4eb21d93b2..18eefa21ad 100644 --- a/server/pypi/packages/pydantic-core/meta.yaml +++ b/server/pypi/packages/pydantic-core/meta.yaml @@ -1,6 +1,6 @@ package: name: pydantic-core - version: "2.41.4" + version: "2.41.5" requirements: build: