diff --git a/python3-dev/build.sh b/python3-dev/build.sh new file mode 100755 index 0000000..9d9a3d1 --- /dev/null +++ b/python3-dev/build.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +set -e + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" +cd "$DIR" + +VERSION="3.12.8" +INSTALL_DIR="$DIR/python3_dev/install" + +# Idempotent: skip if already present +if [ -f "$INSTALL_DIR/include/Python.h" ]; then + echo "python3-dev headers already present, skipping." + exit 0 +fi + +TARBALL="Python-${VERSION}.tgz" +URL="https://www.python.org/ftp/python/${VERSION}/${TARBALL}" + +echo "Downloading CPython ${VERSION} source ..." +curl -fSL -o "$TARBALL" "$URL" + +echo "Extracting ..." +tar xzf "$TARBALL" + +cd "Python-${VERSION}" + +# Run configure to generate pyconfig.h for this platform +echo "Running configure to generate pyconfig.h ..." +./configure --disable-shared --without-ensurepip > /dev/null 2>&1 + +cd "$DIR" + +# Copy headers +rm -rf "$INSTALL_DIR" +mkdir -p "$INSTALL_DIR/include" + +cp -r "Python-${VERSION}/Include/"* "$INSTALL_DIR/include/" +cp "Python-${VERSION}/pyconfig.h" "$INSTALL_DIR/include/" + +# Clean up +rm -rf "Python-${VERSION}" "$TARBALL" + +echo "Installed python3-dev headers to $INSTALL_DIR" +du -sh "$INSTALL_DIR" diff --git a/python3-dev/pyproject.toml b/python3-dev/pyproject.toml new file mode 100644 index 0000000..72b02ce --- /dev/null +++ b/python3-dev/pyproject.toml @@ -0,0 +1,15 @@ +[build-system] +requires = ["setuptools>=64", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "python3-dev" +version = "3.12.8" +description = "CPython development headers" +requires-python = ">=3.8" + +[tool.setuptools.packages.find] +include = ["python3_dev*"] + +[tool.setuptools.package-data] +python3_dev = ["install/**/*"] diff --git a/python3-dev/python3_dev/__init__.py b/python3-dev/python3_dev/__init__.py new file mode 100644 index 0000000..aba381f --- /dev/null +++ b/python3-dev/python3_dev/__init__.py @@ -0,0 +1,9 @@ +import os + +DIR = os.path.join(os.path.dirname(__file__), "install") +INCLUDE_DIR = os.path.join(DIR, "include") + + +def smoketest(): + assert os.path.isfile(os.path.join(INCLUDE_DIR, "Python.h")), "Python.h not found" + assert os.path.isfile(os.path.join(INCLUDE_DIR, "pyconfig.h")), "pyconfig.h not found" diff --git a/python3-dev/setup.py b/python3-dev/setup.py new file mode 100644 index 0000000..b997ab2 --- /dev/null +++ b/python3-dev/setup.py @@ -0,0 +1,61 @@ +import os +import platform +import subprocess + +from setuptools.command.build_py import build_py + +try: + from wheel.bdist_wheel import bdist_wheel +except ImportError: + bdist_wheel = None + + +class BuildPython3Dev(build_py): + """Run build.sh to download CPython headers before collecting package data.""" + + def run(self): + pkg_dir = os.path.dirname(os.path.abspath(__file__)) + marker = os.path.join(pkg_dir, "python3_dev", "install", "include", "Python.h") + + if not os.path.exists(marker): + build_script = os.path.join(pkg_dir, "build.sh") + subprocess.check_call(["bash", build_script], cwd=pkg_dir) + + super().run() + + +cmdclass = {"build_py": BuildPython3Dev} + +if bdist_wheel is not None: + + class PlatformWheel(bdist_wheel): + """Produce a platform-specific, Python-version-agnostic wheel.""" + + def finalize_options(self): + super().finalize_options() + self.root_is_pure = False + + def get_tag(self): + system = platform.system() + machine = platform.machine() + + if system == "Linux": + plat = f"linux_{machine}" + elif system == "Darwin": + plat = "macosx_11_0_arm64" + else: + plat = f"{system.lower()}_{machine}" + + return "py3", "none", plat + + cmdclass["bdist_wheel"] = PlatformWheel + + +def setup(): + from setuptools import setup as _setup + + _setup(cmdclass=cmdclass) + + +if __name__ == "__main__": + setup()