diff --git a/.github/workflows/apple.yml b/.github/workflows/apple.yml index 8e46ec30..b36a6064 100644 --- a/.github/workflows/apple.yml +++ b/.github/workflows/apple.yml @@ -114,6 +114,19 @@ jobs: py: 'cpython-3.12' optimizations: 'pgo+lto' + - target_triple: 'aarch64-apple-darwin' + runner: macos-14 + py: 'cpython-3.13' + optimizations: 'debug' + - target_triple: 'aarch64-apple-darwin' + runner: macos-14 + py: 'cpython-3.13' + optimizations: 'pgo' + - target_triple: 'aarch64-apple-darwin' + runner: macos-14 + py: 'cpython-3.13' + optimizations: 'pgo+lto' + # macOS on Intel hardware. This is pretty straightforward. We exclude # noopt because it doesn't provide any compelling advantages over PGO # or LTO builds. @@ -181,6 +194,19 @@ jobs: runner: macos-13 py: 'cpython-3.12' optimizations: 'pgo+lto' + + - target_triple: 'x86_64-apple-darwin' + runner: macos-13 + py: 'cpython-3.13' + optimizations: 'debug' + - target_triple: 'x86_64-apple-darwin' + runner: macos-13 + py: 'cpython-3.13' + optimizations: 'pgo' + - target_triple: 'x86_64-apple-darwin' + runner: macos-13 + py: 'cpython-3.13' + optimizations: 'pgo+lto' needs: - pythonbuild runs-on: ${{ matrix.build.runner }} diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 364d982e..4c354cc2 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -175,6 +175,16 @@ jobs: py: 'cpython-3.12' optimizations: 'lto' + - target_triple: 'aarch64-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'debug' + - target_triple: 'aarch64-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'noopt' + - target_triple: 'aarch64-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'lto' + # Cross-compiles can't do PGO and require Python 3.9. - target_triple: 'armv7-unknown-linux-gnueabi' py: 'cpython-3.9' @@ -216,6 +226,16 @@ jobs: py: 'cpython-3.12' optimizations: 'lto' + - target_triple: 'armv7-unknown-linux-gnueabi' + py: 'cpython-3.13' + optimizations: 'debug' + - target_triple: 'armv7-unknown-linux-gnueabi' + py: 'cpython-3.13' + optimizations: 'noopt' + - target_triple: 'armv7-unknown-linux-gnueabi' + py: 'cpython-3.13' + optimizations: 'lto' + # Cross-compiles can't do PGO and require Python 3.9. - target_triple: 'armv7-unknown-linux-gnueabihf' py: 'cpython-3.9' @@ -257,6 +277,16 @@ jobs: py: 'cpython-3.12' optimizations: 'lto' + - target_triple: 'armv7-unknown-linux-gnueabihf' + py: 'cpython-3.13' + optimizations: 'debug' + - target_triple: 'armv7-unknown-linux-gnueabihf' + py: 'cpython-3.13' + optimizations: 'noopt' + - target_triple: 'armv7-unknown-linux-gnueabihf' + py: 'cpython-3.13' + optimizations: 'lto' + # Cross-compiles can't do PGO and require Python 3.9. - target_triple: 'mips-unknown-linux-gnu' py: 'cpython-3.9' @@ -298,6 +328,16 @@ jobs: py: 'cpython-3.12' optimizations: 'lto' + - target_triple: 'mips-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'debug' + - target_triple: 'mips-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'noopt' + - target_triple: 'mips-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'lto' + # Cross-compiles can't do PGO and require Python 3.9. - target_triple: 'mipsel-unknown-linux-gnu' py: 'cpython-3.9' @@ -339,6 +379,16 @@ jobs: py: 'cpython-3.12' optimizations: 'lto' + - target_triple: 'mipsel-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'debug' + - target_triple: 'mipsel-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'noopt' + - target_triple: 'mipsel-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'lto' + # Cross-compiles can't do PGO and require Python 3.9. - target_triple: 's390x-unknown-linux-gnu' py: 'cpython-3.9' @@ -380,6 +430,16 @@ jobs: py: 'cpython-3.12' optimizations: 'lto' + - target_triple: 's390x-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'debug' + - target_triple: 's390x-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'noopt' + - target_triple: 's390x-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'lto' + # Cross-compiles can't do PGO and require Python 3.9. - target_triple: 'ppc64le-unknown-linux-gnu' py: 'cpython-3.9' @@ -421,6 +481,16 @@ jobs: py: 'cpython-3.12' optimizations: 'lto' + - target_triple: 'ppc64le-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'debug' + - target_triple: 'ppc64le-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'noopt' + - target_triple: 'ppc64le-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'lto' + # We don't publish noopt builds when PGO is available. - target_triple: 'x86_64-unknown-linux-gnu' py: 'cpython-3.8' @@ -487,6 +557,19 @@ jobs: optimizations: 'pgo+lto' run: true + - target_triple: 'x86_64-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'debug' + run: true + - target_triple: 'x86_64-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'pgo' + run: true + - target_triple: 'x86_64-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'pgo+lto' + run: true + - target_triple: 'x86_64_v2-unknown-linux-gnu' py: 'cpython-3.9' optimizations: 'debug' @@ -539,6 +622,19 @@ jobs: optimizations: 'pgo+lto' run: true + - target_triple: 'x86_64_v2-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'debug' + run: true + - target_triple: 'x86_64_v2-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'pgo' + run: true + - target_triple: 'x86_64_v2-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'pgo+lto' + run: true + - target_triple: 'x86_64_v3-unknown-linux-gnu' py: 'cpython-3.9' optimizations: 'debug' @@ -591,6 +687,19 @@ jobs: optimizations: 'pgo+lto' run: true + - target_triple: 'x86_64_v3-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'debug' + run: true + - target_triple: 'x86_64_v3-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'pgo' + run: true + - target_triple: 'x86_64_v3-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'pgo+lto' + run: true + # GitHub Actions runners don't support x86-64-v4 so we can't PGO. - target_triple: 'x86_64_v4-unknown-linux-gnu' py: 'cpython-3.9' @@ -633,6 +742,16 @@ jobs: py: 'cpython-3.12' optimizations: 'lto' + - target_triple: 'x86_64_v4-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'debug' + - target_triple: 'x86_64_v4-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'noopt' + - target_triple: 'x86_64_v4-unknown-linux-gnu' + py: 'cpython-3.13' + optimizations: 'lto' + # musl doesn't support PGO. - target_triple: 'x86_64-unknown-linux-musl' py: 'cpython-3.8' @@ -699,6 +818,19 @@ jobs: optimizations: 'lto' run: true + - target_triple: 'x86_64-unknown-linux-musl' + py: 'cpython-3.13' + optimizations: 'debug' + run: true + - target_triple: 'x86_64-unknown-linux-musl' + py: 'cpython-3.13' + optimizations: 'noopt' + run: true + - target_triple: 'x86_64-unknown-linux-musl' + py: 'cpython-3.13' + optimizations: 'lto' + run: true + - target_triple: 'x86_64_v2-unknown-linux-musl' py: 'cpython-3.9' optimizations: 'debug' @@ -751,6 +883,19 @@ jobs: optimizations: 'lto' run: true + - target_triple: 'x86_64_v2-unknown-linux-musl' + py: 'cpython-3.13' + optimizations: 'debug' + run: true + - target_triple: 'x86_64_v2-unknown-linux-musl' + py: 'cpython-3.13' + optimizations: 'noopt' + run: true + - target_triple: 'x86_64_v2-unknown-linux-musl' + py: 'cpython-3.13' + optimizations: 'lto' + run: true + - target_triple: 'x86_64_v3-unknown-linux-musl' py: 'cpython-3.9' optimizations: 'debug' @@ -803,6 +948,19 @@ jobs: optimizations: 'lto' run: true + - target_triple: 'x86_64_v3-unknown-linux-musl' + py: 'cpython-3.13' + optimizations: 'debug' + run: true + - target_triple: 'x86_64_v3-unknown-linux-musl' + py: 'cpython-3.13' + optimizations: 'noopt' + run: true + - target_triple: 'x86_64_v3-unknown-linux-musl' + py: 'cpython-3.13' + optimizations: 'lto' + run: true + - target_triple: 'x86_64_v4-unknown-linux-musl' py: 'cpython-3.9' optimizations: 'debug' @@ -843,6 +1001,16 @@ jobs: py: 'cpython-3.12' optimizations: 'lto' + - target_triple: 'x86_64_v4-unknown-linux-musl' + py: 'cpython-3.13' + optimizations: 'debug' + - target_triple: 'x86_64_v4-unknown-linux-musl' + py: 'cpython-3.13' + optimizations: 'noopt' + - target_triple: 'x86_64_v4-unknown-linux-musl' + py: 'cpython-3.13' + optimizations: 'lto' + needs: - pythonbuild - image diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 2f2b5f3c..413cdd3f 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -54,6 +54,7 @@ jobs: - 'cpython-3.10' - 'cpython-3.11' - 'cpython-3.12' + - 'cpython-3.13' vcvars: - 'vcvars32.bat' - 'vcvars64.bat' diff --git a/cpython-unix/Makefile b/cpython-unix/Makefile index 08488956..d3225451 100644 --- a/cpython-unix/Makefile +++ b/cpython-unix/Makefile @@ -270,6 +270,8 @@ $(OUTDIR)/cpython-3.11-$(CPYTHON_3.11_VERSION)-$(HOST_PLATFORM).tar: $(PYTHON_HO $(OUTDIR)/cpython-3.12-$(CPYTHON_3.12_VERSION)-$(HOST_PLATFORM).tar: $(PYTHON_HOST_DEPENDS) $(RUN_BUILD) --docker-image $(DOCKER_IMAGE_BUILD) cpython-3.12-host +$(OUTDIR)/cpython-3.13-$(CPYTHON_3.13_VERSION)-$(HOST_PLATFORM).tar: $(PYTHON_HOST_DEPENDS) + $(RUN_BUILD) --docker-image $(DOCKER_IMAGE_BUILD) cpython-3.13-host PYTHON_DEPENDS := \ $(PYTHON_SUPPORT_FILES) \ @@ -318,3 +320,6 @@ $(OUTDIR)/cpython-$(CPYTHON_3.11_VERSION)-$(PACKAGE_SUFFIX).tar: $(ALL_PYTHON_DE $(OUTDIR)/cpython-$(CPYTHON_3.12_VERSION)-$(PACKAGE_SUFFIX).tar: $(ALL_PYTHON_DEPENDS) $(RUN_BUILD) --docker-image $(DOCKER_IMAGE_BUILD) cpython-3.12 + +$(OUTDIR)/cpython-$(CPYTHON_3.13_VERSION)-$(PACKAGE_SUFFIX).tar: $(ALL_PYTHON_DEPENDS) + $(RUN_BUILD) --docker-image $(DOCKER_IMAGE_BUILD) cpython-3.13 diff --git a/cpython-unix/build-cpython-host.sh b/cpython-unix/build-cpython-host.sh index cfc1e8a7..338219ad 100755 --- a/cpython-unix/build-cpython-host.sh +++ b/cpython-unix/build-cpython-host.sh @@ -38,11 +38,18 @@ pushd "Python-${PYTHON_VERSION}" # configure. This is reported as https://bugs.python.org/issue45405. We nerf the # check since we know what we're doing. if [ "${CC}" = "clang" ]; then - if [ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_9}" ]; then + if [ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_13}" ]; then + patch -p1 -i ${ROOT}/patch-disable-multiarch-13.patch + elif [ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_9}" ]; then patch -p1 -i ${ROOT}/patch-disable-multiarch.patch else patch -p1 -i ${ROOT}/patch-disable-multiarch-legacy.patch fi +elif [ "${CC}" = "musl-clang" ]; then + # Similarly, this is a problem for musl Clang on Python 3.13+ + if [ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_13}" ]; then + patch -p1 -i ${ROOT}/patch-disable-multiarch-13.patch + fi fi autoconf diff --git a/cpython-unix/build-cpython.sh b/cpython-unix/build-cpython.sh index 87225429..10476a36 100755 --- a/cpython-unix/build-cpython.sh +++ b/cpython-unix/build-cpython.sh @@ -72,7 +72,10 @@ cat Makefile.extra pushd Python-${PYTHON_VERSION} # configure doesn't support cross-compiling on Apple. Teach it. -if [ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_12}" ]; then +if [ "${PYTHON_MAJMIN_VERSION}" = "3.13" ]; then + # TODO: Add support for cross-compiling on 3.13 + : +elif [ "${PYTHON_MAJMIN_VERSION}" = "3.12" ]; then patch -p1 -i ${ROOT}/patch-apple-cross-3.12.patch else patch -p1 -i ${ROOT}/patch-apple-cross.patch @@ -94,7 +97,9 @@ fi # Configure nerfs RUNSHARED when cross-compiling, which prevents PGO from running when # we can in fact run the target binaries (e.g. x86_64 host and i686 target). Undo that. if [ -n "${CROSS_COMPILING}" ]; then - if [ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_11}" ]; then + if [ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_13}" ]; then + patch -p1 -i ${ROOT}/patch-dont-clear-runshared-13.patch + elif [ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_11}" ]; then patch -p1 -i ${ROOT}/patch-dont-clear-runshared.patch else patch -p1 -i ${ROOT}/patch-dont-clear-runshared-legacy.patch @@ -105,11 +110,18 @@ fi # configure. This is reported as https://bugs.python.org/issue45405. We nerf the # check since we know what we're doing. if [ "${CC}" = "clang" ]; then - if [ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_9}" ]; then + if [ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_13}" ]; then + patch -p1 -i ${ROOT}/patch-disable-multiarch-13.patch + elif [ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_9}" ]; then patch -p1 -i ${ROOT}/patch-disable-multiarch.patch else patch -p1 -i ${ROOT}/patch-disable-multiarch-legacy.patch fi +elif [ "${CC}" = "musl-clang" ]; then + # Similarly, this is a problem for musl Clang on Python 3.13+ + if [ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_13}" ]; then + patch -p1 -i ${ROOT}/patch-disable-multiarch-13.patch + fi fi # Python 3.11 supports using a provided Python to use during bootstrapping @@ -134,9 +146,19 @@ if [ -n "${PYTHON_MEETS_MAXIMUM_VERSION_3_10}" ]; then patch -p1 -i ${ROOT}/patch-makesetup-deduplicate-objs.patch fi +# testembed links against Tcl/Tk and libpython which already includes Tcl/Tk leading duplicate +# symbols and warnings from objc (which then causes failures in `test_embed` during PGO). +if [ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_13}" ]; then + patch -p1 -i ${ROOT}/patch-make-testembed-nolink-tcltk.patch +fi + # The default build rule for the macOS dylib doesn't pick up libraries # from modules / makesetup. So patch it accordingly. -patch -p1 -i ${ROOT}/patch-macos-link-extension-modules.patch +if [ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_13}" ]; then + patch -p1 -i ${ROOT}/patch-macos-link-extension-modules-13.patch +else + patch -p1 -i ${ROOT}/patch-macos-link-extension-modules.patch +fi # Also on macOS, the `python` executable is linked against libraries defined by statically # linked modules. But those libraries should only get linked into libpython, not the @@ -280,7 +302,7 @@ if [ "${PYBUILD_PLATFORM}" != "macos" ]; then fi fi -# On Python 3.12 we need to link the special hacl library provided some SHA-256 +# On Python 3.12+ we need to link the special hacl library provided some SHA-256 # implementations. Since we hack up the regular extension building mechanism, we # need to reinvent this wheel. if [ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_12}" ]; then @@ -336,7 +358,12 @@ fi if [ -n "${CPYTHON_OPTIMIZED}" ]; then CONFIGURE_FLAGS="${CONFIGURE_FLAGS} --enable-optimizations" - if [[ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_12}" && -n "${BOLT_CAPABLE}" ]]; then + if [[ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_13}" && -n "${BOLT_CAPABLE}" ]]; then + # Due to a SEGFAULT when running `test_embed` with BOLT instrumented binaries, we can't use + # BOLT on Python 3.13+. + # TODO: Find a fix for this or consider skipping these tests specifically + echo "BOLT is disabled on Python 3.13+" + elif [[ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_12}" && -n "${BOLT_CAPABLE}" ]]; then CONFIGURE_FLAGS="${CONFIGURE_FLAGS} --enable-bolt" fi fi @@ -426,6 +453,11 @@ if [ "${PYBUILD_PLATFORM}" = "macos" ]; then export MACOSX_DEPLOYMENT_TARGET="${APPLE_MIN_DEPLOYMENT_TARGET}" fi +# ptsrname_r is only available in SDK 13.4+, but we target a lower version for compatibility. +if [ "${PYBUILD_PLATFORM}" = "macos" ]; then + CONFIGURE_FLAGS="${CONFIGURE_FLAGS} ac_cv_func_ptsname_r=no" +fi + # We use ndbm on macOS and BerkeleyDB elsewhere. if [ "${PYBUILD_PLATFORM}" = "macos" ]; then CONFIGURE_FLAGS="${CONFIGURE_FLAGS} --with-dbmliborder=ndbm" @@ -742,7 +774,13 @@ s390x-unknown-linux-gnu) PYTHON_ARCH="s390x-linux-gnu" ;; x86_64-unknown-linux-*) - PYTHON_ARCH="x86_64-linux-gnu" + # In Python 3.13+, the musl target is identified in cross compiles and the output directory + # is named accordingly. + if [ "${CC}" = "musl-clang" ] && [ "${PYTHON_MAJMIN_VERSION}" = "3.13" ]; then + PYTHON_ARCH="x86_64-linux-musl" + else + PYTHON_ARCH="x86_64-linux-gnu" + fi ;; *) echo "unhandled target triple: ${TARGET_TRIPLE}" @@ -832,7 +870,7 @@ ${BUILD_PYTHON} ${ROOT}/fix_shebangs.py ${ROOT}/out/python/install # downstream consumers. OBJECT_DIRS="Objects Parser Parser/pegen Programs Python" OBJECT_DIRS="${OBJECT_DIRS} Modules" -for ext in _blake2 cjkcodecs _ctypes _ctypes/darwin _decimal _expat _hacl _io _multiprocessing _sha3 _sqlite _sre _xxtestfuzz ; do +for ext in _blake2 cjkcodecs _ctypes _ctypes/darwin _decimal _expat _hacl _io _multiprocessing _sha3 _sqlite _sre _testinternalcapi _xxtestfuzz ; do OBJECT_DIRS="${OBJECT_DIRS} Modules/${ext}" done @@ -895,7 +933,12 @@ cp -av Python/frozen.c ${ROOT}/out/python/build/Python/ cp -av Modules/Setup* ${ROOT}/out/python/build/Modules/ # Copy the test hardness runner for convenience. -cp -av Tools/scripts/run_tests.py ${ROOT}/out/python/build/ +# As of Python 3.13, the test harness runner has been removed so we provide a compatibility script +if [ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_13}" ]; then + cp -av ${ROOT}/run_tests-13.py ${ROOT}/out/python/build/run_tests.py +else + cp -av Tools/scripts/run_tests.py ${ROOT}/out/python/build/ +fi mkdir ${ROOT}/out/python/licenses cp ${ROOT}/LICENSE.*.txt ${ROOT}/out/python/licenses/ diff --git a/cpython-unix/build-main.py b/cpython-unix/build-main.py index b9b3c5dc..34a90d19 100755 --- a/cpython-unix/build-main.py +++ b/cpython-unix/build-main.py @@ -67,6 +67,7 @@ def main(): "cpython-3.10", "cpython-3.11", "cpython-3.12", + "cpython-3.13", }, default="cpython-3.11", help="Python distribution to build", diff --git a/cpython-unix/build.py b/cpython-unix/build.py index ccea702c..5c32586b 100755 --- a/cpython-unix/build.py +++ b/cpython-unix/build.py @@ -435,6 +435,7 @@ def build_cpython_host( support = { "build-cpython-host.sh", "patch-disable-multiarch.patch", + "patch-disable-multiarch-13.patch", "patch-disable-multiarch-legacy.patch", } for s in sorted(support): @@ -455,7 +456,7 @@ def build_cpython_host( # Set environment variables allowing convenient testing for Python # version ranges. - for v in ("3.8", "3.9", "3.10", "3.11", "3.12"): + for v in ("3.8", "3.9", "3.10", "3.11", "3.12", "3.13"): normal_version = v.replace(".", "_") if meets_python_minimum_version(python_version, v): @@ -745,6 +746,7 @@ def build_cpython( setuptools_archive, pip_archive, SUPPORT / "build-cpython.sh", + SUPPORT / "run_tests-13.py", ): build_env.copy_file(p) @@ -782,7 +784,7 @@ def build_cpython( # Set environment variables allowing convenient testing for Python # version ranges. - for v in ("3.8", "3.9", "3.10", "3.11", "3.12"): + for v in ("3.8", "3.9", "3.10", "3.11", "3.12", "3.13"): normal_version = v.replace(".", "_") if meets_python_minimum_version(python_version, v): @@ -1195,6 +1197,7 @@ def main(): "cpython-3.10", "cpython-3.11", "cpython-3.12", + "cpython-3.13", ): build_cpython( settings, diff --git a/cpython-unix/extension-modules.yml b/cpython-unix/extension-modules.yml index 37f78101..3c580dee 100644 --- a/cpython-unix/extension-modules.yml +++ b/cpython-unix/extension-modules.yml @@ -67,6 +67,7 @@ _contextvars: - _contextvarsmodule.c _crypt: + maximum-python-version: "3.12" build-mode: shared sources: - _cryptmodule.c @@ -286,6 +287,21 @@ _heapq: _imp: config-c-only: true +_interpchannels: + minimum-python-version: "3.13" + sources: + - _interpchannelsmodule.c + +_interpqueues: + minimum-python-version: "3.13" + sources: + - _interpqueuesmodule.c + +_interpreters: + minimum-python-version: "3.13" + sources: + - _interpretersmodule.c + _io: setup-enabled: true required-targets: @@ -528,9 +544,21 @@ _struct: sources: - _struct.c +_suggestions: + setup-enabled: true + minimum-python-version: '3.13' + sources: + - _suggestions.c + _symtable: setup-enabled: true +_sysconfig: + setup-enabled: true + minimum-python-version: '3.13' + sources: + - _sysconfig.c + _testbuffer: minimum-python-version: '3.9' sources: @@ -545,6 +573,11 @@ _testcapi: sources: - _testcapimodule.c +_testexternalinspection: + minimum-python-version: '3.13' + sources: + - _testexternalinspection.c + _testimportmultiple: minimum-python-version: '3.9' sources: @@ -558,6 +591,18 @@ _testinternalcapi: - Include/internal sources: - _testinternalcapi.c + includes-conditional: + - path: _testinternalcapi/parts.h + minimum-python-version: "3.13" + sources-conditional: + - source: _testinternalcapi/pytime.c + minimum-python-version: "3.13" + - source: _testinternalcapi/set.c + minimum-python-version: "3.13" + - source: _testinternalcapi/test_critical_sections.c + minimum-python-version: "3.13" + - source: _testinternalcapi/test_lock.c + minimum-python-version: "3.13" _testmultiphase: minimum-python-version: '3.9' @@ -659,11 +704,13 @@ _weakref: _xxinterpchannels: minimum-python-version: '3.12' + maximum-python-version: '3.12' sources: - _xxinterpchannelsmodule.c _xxsubinterpreters: minimum-python-version: '3.9' + maximum-python-version: '3.12' sources: - _xxsubinterpretersmodule.c @@ -687,6 +734,7 @@ atexit: # Modules/Setup comment is ambiguous as to whether this module actually works. audioop: + maximum-python-version: '3.12' sources: - audioop.c @@ -745,6 +793,7 @@ mmap: - mmapmodule.c nis: + maximum-python-version: "3.12" disabled-targets: # NIS is not available on Apple OS. - aarch64-apple-.* @@ -767,6 +816,7 @@ nis: - nsl ossaudiodev: + maximum-python-version: "3.12" disabled-targets: # ossaudiodev not available on Apple OS. - aarch64-apple-.* @@ -806,6 +856,8 @@ readline: - readline.c defines: - USE_LIBEDIT=1 + # While some versions do not, our readline `on_startup_hook` takes arguments. + - Py_RL_STARTUP_HOOK_TAKES_ARGS includes-deps: - libedit/include - libedit/include/ncursesw @@ -828,6 +880,7 @@ select: - selectmodule.c spwd: + maximum-python-version: "3.12" sources: - spwdmodule.c diff --git a/cpython-unix/patch-disable-multiarch-13.patch b/cpython-unix/patch-disable-multiarch-13.patch new file mode 100644 index 00000000..3ff33246 --- /dev/null +++ b/cpython-unix/patch-disable-multiarch-13.patch @@ -0,0 +1,17 @@ +diff -u 13-a/configure.ac 13-b/configure.ac +--- 13-a/configure.ac 2024-05-08 05:21:00.000000000 -0400 ++++ 13-b/configure.ac 2024-05-19 07:42:23.294762624 -0400 +@@ -1090,12 +1090,7 @@ + dnl architecture. PLATFORM_TRIPLET will be a pair or single value for these + dnl platforms. + AC_MSG_CHECKING([for multiarch]) +-AS_CASE([$ac_sys_system], +- [Darwin*], [MULTIARCH=""], +- [iOS], [MULTIARCH=""], +- [FreeBSD*], [MULTIARCH=""], +- [MULTIARCH=$($CC --print-multiarch 2>/dev/null)] +-) ++MULTIARCH= + AC_SUBST([MULTIARCH]) + + if test x$PLATFORM_TRIPLET != x && test x$MULTIARCH != x; then diff --git a/cpython-unix/patch-dont-clear-runshared-13.patch b/cpython-unix/patch-dont-clear-runshared-13.patch new file mode 100644 index 00000000..7dcba084 --- /dev/null +++ b/cpython-unix/patch-dont-clear-runshared-13.patch @@ -0,0 +1,14 @@ +diff -u 13-a/configure.ac 13-b/configure.ac +--- 13-a/configure.ac 2024-05-08 05:21:00.000000000 -0400 ++++ 13-b/configure.ac 2024-05-19 12:44:04.530770938 -0400 +@@ -1564,10 +1564,6 @@ + fi + AC_MSG_RESULT([$LDLIBRARY]) + +-if test "$cross_compiling" = yes; then +- RUNSHARED= +-fi +- + AC_MSG_CHECKING([HOSTRUNNER]) + AC_ARG_VAR([HOSTRUNNER], [Program to run CPython for the host platform]) + if test -z "$HOSTRUNNER" diff --git a/cpython-unix/patch-macos-link-extension-modules-13.patch b/cpython-unix/patch-macos-link-extension-modules-13.patch new file mode 100644 index 00000000..75b0d781 --- /dev/null +++ b/cpython-unix/patch-macos-link-extension-modules-13.patch @@ -0,0 +1,12 @@ +diff -u 13-a/Makefile.pre.in 13-b/Makefile.pre.in +--- 13-a/Makefile.pre.in 2024-05-08 05:21:00.000000000 -0400 ++++ 13-b/Makefile.pre.in 2024-05-19 07:55:45.091521909 -0400 +@@ -903,7 +903,7 @@ + $(BLDSHARED) $(NO_AS_NEEDED) -o $@ -Wl,-h$@ $^ + + libpython$(LDVERSION).dylib: $(LIBRARY_OBJS) +- $(CC) -dynamiclib $(PY_CORE_LDFLAGS) -undefined dynamic_lookup -Wl,-install_name,$(prefix)/lib/libpython$(LDVERSION).dylib -Wl,-compatibility_version,$(VERSION) -Wl,-current_version,$(VERSION) -o $@ $(LIBRARY_OBJS) $(DTRACE_OBJS) $(SHLIBS) $(LIBC) $(LIBM); \ ++ $(CC) -dynamiclib $(PY_CORE_LDFLAGS) -undefined dynamic_lookup -Wl,-install_name,$(prefix)/lib/libpython$(LDVERSION).dylib -Wl,-compatibility_version,$(VERSION) -Wl,-current_version,$(VERSION) -o $@ $(LIBRARY_OBJS) $(DTRACE_OBJS) $(MODLIBS) $(SHLIBS) $(LIBC) $(LIBM); \ + + + libpython$(VERSION).sl: $(LIBRARY_OBJS) diff --git a/cpython-unix/patch-make-testembed-nolink-tcltk.patch b/cpython-unix/patch-make-testembed-nolink-tcltk.patch new file mode 100644 index 00000000..65c1989f --- /dev/null +++ b/cpython-unix/patch-make-testembed-nolink-tcltk.patch @@ -0,0 +1,10 @@ +diff --git a/Makefile.pre.in b/Makefile.pre.in +--- a/Makefile.pre.in ++++ b/Makefile.pre.in +@@ -1432,6 +1432,8 @@ + $(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Tools/build/generate_re_casefix.py $(srcdir)/Lib/re/_casefix.py + + Programs/_testembed: Programs/_testembed.o $(LINK_PYTHON_DEPS) ++ $(eval MODLIBS := $(subst -Xlinker -hidden-ltcl8.6, , $(MODLIBS))) ++ $(eval MODLIBS := $(subst -Xlinker -hidden-ltk8.6, , $(MODLIBS))) + $(LINKCC) $(PY_CORE_LDFLAGS) $(LINKFORSHARED) -o $@ Programs/_testembed.o $(LINK_PYTHON_OBJS) $(LIBS) $(MODLIBS) $(SYSLIBS) diff --git a/cpython-unix/run_tests-13.py b/cpython-unix/run_tests-13.py new file mode 100644 index 00000000..a78210cc --- /dev/null +++ b/cpython-unix/run_tests-13.py @@ -0,0 +1,30 @@ +""" +Run Python's test suite. + +As of Python 3.13, this script is no longer included in Python itself. +Instead, use: + + $ python -m test --slow-ci + +""" + +import os +import sys + + +def main(regrtest_args): + args = [ + sys.executable, + "-m", + "test", + "--slow-ci", + ] + + args.extend(regrtest_args) + print(" ".join(args)) + + os.execv(sys.executable, args) + + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/cpython-unix/targets.yml b/cpython-unix/targets.yml index fd81e286..02e41311 100644 --- a/cpython-unix/targets.yml +++ b/cpython-unix/targets.yml @@ -64,6 +64,7 @@ aarch64-apple-darwin: - '3.10' - '3.11' - '3.12' + - '3.13' needs_toolchain: true host_cc: clang host_cxx: clang++ @@ -153,6 +154,7 @@ aarch64-unknown-linux-gnu: - '3.10' - '3.11' - '3.12' + - '3.13' docker_image_suffix: .cross host_cc: /usr/bin/x86_64-linux-gnu-gcc host_cxx: /usr/bin/x86_64-linux-gnu-g++ @@ -231,6 +233,7 @@ armv7-unknown-linux-gnueabi: - '3.10' - '3.11' - '3.12' + - '3.13' docker_image_suffix: .cross host_cc: /usr/bin/x86_64-linux-gnu-gcc host_cxx: /usr/bin/x86_64-linux-gnu-g++ @@ -269,6 +272,7 @@ armv7-unknown-linux-gnueabihf: - '3.10' - '3.11' - '3.12' + - '3.13' docker_image_suffix: .cross host_cc: /usr/bin/x86_64-linux-gnu-gcc host_cxx: /usr/bin/x86_64-linux-gnu-g++ @@ -308,6 +312,7 @@ i686-unknown-linux-gnu: - '3.10' - '3.11' - '3.12' + - '3.13' needs_toolchain: true host_cc: clang host_cxx: clang++ @@ -351,6 +356,7 @@ mips-unknown-linux-gnu: - '3.10' - '3.11' - '3.12' + - '3.13' docker_image_suffix: .cross host_cc: /usr/bin/x86_64-linux-gnu-gcc host_cxx: /usr/bin/x86_64-linux-gnu-g++ @@ -389,6 +395,7 @@ mipsel-unknown-linux-gnu: - '3.10' - '3.11' - '3.12' + - '3.13' docker_image_suffix: .cross host_cc: /usr/bin/x86_64-linux-gnu-gcc host_cxx: /usr/bin/x86_64-linux-gnu-g++ @@ -427,6 +434,7 @@ ppc64le-unknown-linux-gnu: - '3.10' - '3.11' - '3.12' + - '3.13' docker_image_suffix: .cross host_cc: /usr/bin/x86_64-linux-gnu-gcc host_cxx: /usr/bin/x86_64-linux-gnu-g++ @@ -465,6 +473,7 @@ s390x-unknown-linux-gnu: - '3.10' - '3.11' - '3.12' + - '3.13' docker_image_suffix: .cross host_cc: /usr/bin/x86_64-linux-gnu-gcc host_cxx: /usr/bin/x86_64-linux-gnu-g++ @@ -548,6 +557,7 @@ x86_64-apple-darwin: - '3.10' - '3.11' - '3.12' + - '3.13' needs_toolchain: true apple_sdk_platform: macosx host_cc: clang @@ -717,6 +727,7 @@ x86_64-unknown-linux-gnu: - '3.10' - '3.11' - '3.12' + - '3.13' needs_toolchain: true host_cc: clang host_cxx: clang++ @@ -761,6 +772,7 @@ x86_64_v2-unknown-linux-gnu: - '3.10' - '3.11' - '3.12' + - '3.13' needs_toolchain: true host_cc: clang host_cxx: clang++ @@ -806,6 +818,7 @@ x86_64_v3-unknown-linux-gnu: - '3.10' - '3.11' - '3.12' + - '3.13' needs_toolchain: true host_cc: clang host_cxx: clang++ @@ -851,6 +864,7 @@ x86_64_v4-unknown-linux-gnu: - '3.10' - '3.11' - '3.12' + - '3.13' needs_toolchain: true host_cc: clang host_cxx: clang++ @@ -896,6 +910,7 @@ x86_64-unknown-linux-musl: - '3.10' - '3.11' - '3.12' + - '3.13' needs_toolchain: true host_cc: clang host_cxx: clang++ @@ -938,6 +953,7 @@ x86_64_v2-unknown-linux-musl: - '3.10' - '3.11' - '3.12' + - '3.13' needs_toolchain: true host_cc: clang host_cxx: clang++ @@ -981,6 +997,7 @@ x86_64_v3-unknown-linux-musl: - '3.10' - '3.11' - '3.12' + - '3.13' needs_toolchain: true host_cc: clang host_cxx: clang++ @@ -1024,6 +1041,7 @@ x86_64_v4-unknown-linux-musl: - '3.10' - '3.11' - '3.12' + - '3.13' needs_toolchain: true host_cc: clang host_cxx: clang++ diff --git a/cpython-windows/build.py b/cpython-windows/build.py index bc97cd57..88bcf6e0 100644 --- a/cpython-windows/build.py +++ b/cpython-windows/build.py @@ -65,7 +65,10 @@ "_lzma": { "ignore_additional_depends": {"$(OutDir)liblzma$(PyDebugExt).lib"}, }, - "_msi": {}, + "_msi": { + # Removed in 3.13. + "ignore_missing": True, + }, "_overlapped": {}, "_multiprocessing": {}, "_socket": {}, @@ -352,6 +355,7 @@ def hack_props( xz_version = DOWNLOADS["xz"]["version"] zlib_version = DOWNLOADS["zlib"]["version"] tcltk_commit = DOWNLOADS["tk-windows-bin"]["git_commit"] + mpdecimal_version = DOWNLOADS["mpdecimal"]["version"] sqlite_path = td / ("sqlite-autoconf-%s" % sqlite_version) bzip2_path = td / ("bzip2-%s" % bzip2_version) @@ -359,6 +363,7 @@ def hack_props( tcltk_path = td / ("cpython-bin-deps-%s" % tcltk_commit) xz_path = td / ("xz-%s" % xz_version) zlib_path = td / ("zlib-%s" % zlib_version) + mpdecimal_path = td / ("mpdecimal-%s" % mpdecimal_version) openssl_root = td / "openssl" / arch openssl_libs_path = openssl_root / "lib" @@ -398,6 +403,9 @@ def hack_props( elif b"%s\\" % zlib_path + elif b"%s\\" % mpdecimal_path + lines.append(line) with python_props_path.open("wb") as fh: @@ -1155,15 +1163,17 @@ def collect_python_build_artifacts( "_ctypes_test", "_testbuffer", "_testcapi", + "_testclinic_limited", "_testclinic", "_testconsole", "_testembed", "_testimportmultiple", "_testinternalcapi", - "_testsinglephase", + "_testlimitedcapi", "_testmultiphase", - "xxlimited", + "_testsinglephase", "xxlimited_35", + "xxlimited", } other_projects = {"pythoncore"} @@ -1409,6 +1419,14 @@ def build_cpython( setuptools_wheel = download_entry("setuptools", BUILD) pip_wheel = download_entry("pip", BUILD) + # CPython 3.13+ no longer uses a bundled `mpdecimal` version so we build it + if meets_python_minimum_version(python_version, "3.13"): + mpdecimal_archive = download_entry("mpdecimal", BUILD) + else: + # TODO: Consider using the built mpdecimal for earlier versions as well, + # as we do for Unix builds. + mpdecimal_archive = None + if arch == "amd64": build_platform = "x64" build_directory = "amd64" @@ -1426,12 +1444,16 @@ def build_cpython( for a in ( python_archive, bzip2_archive, + mpdecimal_archive, openssl_archive, sqlite_archive, tk_bin_archive, xz_archive, zlib_archive, ): + if a is None: + continue + log("extracting %s to %s" % (a, td)) fs.append(e.submit(extract_tar_to_directory, a, td)) @@ -1700,10 +1722,18 @@ def build_cpython( log("copying %s to %s" % (source, dest)) shutil.copyfile(source, dest) - shutil.copyfile( - cpython_source_path / "Tools" / "scripts" / "run_tests.py", - out_dir / "python" / "build" / "run_tests.py", - ) + # CPython 3.13 removed `run_tests.py`, we provide a compatibility script + # for now. + if meets_python_minimum_version(python_version, "3.13"): + shutil.copyfile( + SUPPORT / "run_tests-13.py", + out_dir / "python" / "build" / "run_tests.py", + ) + else: + shutil.copyfile( + cpython_source_path / "Tools" / "scripts" / "run_tests.py", + out_dir / "python" / "build" / "run_tests.py", + ) licenses_dir = out_dir / "python" / "licenses" licenses_dir.mkdir() diff --git a/cpython-windows/run_tests-13.py b/cpython-windows/run_tests-13.py new file mode 100644 index 00000000..f3c165fb --- /dev/null +++ b/cpython-windows/run_tests-13.py @@ -0,0 +1,30 @@ +""" +Run Python's test suite. + +As of Python 3.13, this script is no longer included in Python itself. +Instead, use: + + $ python -m test --slow-ci + +""" + +import sys +from subprocess import call + + +def main(regrtest_args): + args = [ + sys.executable, + "-m", + "test", + "--slow-ci", + ] + + args.extend(regrtest_args) + print(" ".join(args)) + + sys.exit(call(args)) + + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/pythonbuild/cpython.py b/pythonbuild/cpython.py index 97a715d5..c499cc0f 100644 --- a/pythonbuild/cpython.py +++ b/pythonbuild/cpython.py @@ -41,6 +41,8 @@ "properties": { "path": {"type": "string"}, "targets": {"type": "array", "items": {"type": "string"}}, + "minimum-python-version": {"type": "string"}, + "maximum-python-version": {"type": "string"}, }, "additionalProperties": False, }, @@ -534,7 +536,19 @@ def derive_setup_local( line += f" -I{path}" for entry in info.get("includes-conditional", []): - if any(re.match(p, target_triple) for p in entry["targets"]): + if targets := entry.get("targets", []): + target_match = any(re.match(p, target_triple) for p in targets) + else: + target_match = True + + python_min_match = meets_python_minimum_version( + python_version, entry.get("minimum-python-version", "1.0") + ) + python_max_match = meets_python_maximum_version( + python_version, entry.get("maximum-python-version", "100.0") + ) + + if target_match and (python_min_match and python_max_match): line += f" -I{entry['path']}" for path in info.get("includes-deps", []): diff --git a/pythonbuild/downloads.py b/pythonbuild/downloads.py index 16835ac7..c526b3eb 100644 --- a/pythonbuild/downloads.py +++ b/pythonbuild/downloads.py @@ -79,6 +79,15 @@ "license_file": "LICENSE.cpython.txt", "python_tag": "cp312", }, + "cpython-3.13": { + "url": "https://www.python.org/ftp/python/3.13.0/Python-3.13.0rc1.tar.xz", + "size": 20881016, + "sha256": "678b884775eec0224d5159fa900879020baca2a36ce942fd95febfa1adb4a6bd", + "version": "3.13.0rc1", + "licenses": ["Python-2.0", "CNRI-Python"], + "license_file": "LICENSE.cpython.txt", + "python_tag": "cp313", + }, "expat": { "url": "https://github.com/libexpat/libexpat/releases/download/R_2_5_0/expat-2.5.0.tar.xz", "size": 460560, diff --git a/src/validation.rs b/src/validation.rs index 12155132..cbbf3665 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -125,6 +125,7 @@ const PE_ALLOWED_LIBRARIES: &[&str] = &[ "python310.dll", "python311.dll", "python312.dll", + "python313.dll", "sqlite3.dll", "tcl86t.dll", "tk86t.dll", @@ -287,6 +288,16 @@ static DARWIN_ALLOWED_DYLIBS: Lazy> = Lazy::new(|| { max_compatibility_version: "3.12.0".try_into().unwrap(), required: false, }, + MachOAllowedDylib { + name: "@executable_path/../lib/libpython3.13.dylib".to_string(), + max_compatibility_version: "3.13.0".try_into().unwrap(), + required: false, + }, + MachOAllowedDylib { + name: "@executable_path/../lib/libpython3.13d.dylib".to_string(), + max_compatibility_version: "3.13.0".try_into().unwrap(), + required: false, + }, MachOAllowedDylib { name: "/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit".to_string(), max_compatibility_version: "45.0.0".try_into().unwrap(), @@ -638,7 +649,6 @@ const GLOBAL_EXTENSIONS: &[&str] = &[ "_weakref", "array", "atexit", - "audioop", "binascii", "builtins", "cmath", @@ -665,13 +675,15 @@ const GLOBAL_EXTENSIONS: &[&str] = &[ // _testsinglephase added in 3.12. // _sha256 and _sha512 merged into _sha2 in 3.12. // _xxinterpchannels added in 3.12. +// audioop removed in 3.13. // We didn't build ctypes_test until 3.9. // We didn't build some test extensions until 3.9. -const GLOBAL_EXTENSIONS_PYTHON_3_8: &[&str] = &["_sha256", "_sha512", "parser"]; +const GLOBAL_EXTENSIONS_PYTHON_3_8: &[&str] = &["audioop", "_sha256", "_sha512", "parser"]; const GLOBAL_EXTENSIONS_PYTHON_3_9: &[&str] = &[ + "audioop", "_peg_parser", "_sha256", "_sha512", @@ -682,6 +694,7 @@ const GLOBAL_EXTENSIONS_PYTHON_3_9: &[&str] = &[ ]; const GLOBAL_EXTENSIONS_PYTHON_3_10: &[&str] = &[ + "audioop", "_sha256", "_sha512", "_uuid", @@ -690,6 +703,7 @@ const GLOBAL_EXTENSIONS_PYTHON_3_10: &[&str] = &[ ]; const GLOBAL_EXTENSIONS_PYTHON_3_11: &[&str] = &[ + "audioop", "_sha256", "_sha512", "_tokenize", @@ -700,6 +714,7 @@ const GLOBAL_EXTENSIONS_PYTHON_3_11: &[&str] = &[ ]; const GLOBAL_EXTENSIONS_PYTHON_3_12: &[&str] = &[ + "audioop", "_sha2", "_tokenize", "_typing", @@ -708,6 +723,17 @@ const GLOBAL_EXTENSIONS_PYTHON_3_12: &[&str] = &[ "_zoneinfo", ]; +const GLOBAL_EXTENSIONS_PYTHON_3_13: &[&str] = &[ + "_interpchannels", + "_interpqueues", + "_interpreters", + "_sha2", + "_sysconfig", + "_tokenize", + "_typing", + "_zoneinfo", +]; + const GLOBAL_EXTENSIONS_MACOS: &[&str] = &["_scproxy"]; const GLOBAL_EXTENSIONS_POSIX: &[&str] = &[ @@ -729,19 +755,19 @@ const GLOBAL_EXTENSIONS_POSIX: &[&str] = &[ "termios", ]; -const GLOBAL_EXTENSIONS_LINUX: &[&str] = &["spwd"]; +const GLOBAL_EXTENSIONS_LINUX_PRE_3_13: &[&str] = &["spwd"]; const GLOBAL_EXTENSIONS_WINDOWS: &[&str] = &[ - "_msi", "_overlapped", "_winapi", - "_xxsubinterpreters", "msvcrt", "nt", "winreg", "winsound", ]; +const GLOBAL_EXTENSIONS_WINDOWS_PRE_3_13: &[&str] = &["_msi"]; + /// Extension modules not present in Windows static builds. const GLOBAL_EXTENSIONS_WINDOWS_NO_STATIC: &[&str] = &["_testinternalcapi", "_tkinter"]; @@ -1448,6 +1474,9 @@ fn validate_extension_modules( "3.12" => { wanted.extend(GLOBAL_EXTENSIONS_PYTHON_3_12); } + "3.13" => { + wanted.extend(GLOBAL_EXTENSIONS_PYTHON_3_13); + } _ => { panic!("unhandled Python version: {}", python_major_minor); } @@ -1455,12 +1484,23 @@ fn validate_extension_modules( if is_macos { wanted.extend(GLOBAL_EXTENSIONS_POSIX); + if python_major_minor == "3.13" { + wanted.remove("_crypt"); + } wanted.extend(GLOBAL_EXTENSIONS_MACOS); } if is_windows { wanted.extend(GLOBAL_EXTENSIONS_WINDOWS); + if python_major_minor == "3.8" { + wanted.insert("_xxsubinterpreters"); + } + + if matches!(python_major_minor, "3.8" | "3.9" | "3.10" | "3.11" | "3.12") { + wanted.extend(GLOBAL_EXTENSIONS_WINDOWS_PRE_3_13); + } + if static_crt { for x in GLOBAL_EXTENSIONS_WINDOWS_NO_STATIC { wanted.remove(*x); @@ -1470,14 +1510,27 @@ fn validate_extension_modules( if is_linux { wanted.extend(GLOBAL_EXTENSIONS_POSIX); - wanted.extend(GLOBAL_EXTENSIONS_LINUX); + // TODO: If there are more differences for `GLOBAL_EXTENSIONS_POSIX` in future Python + // versions, we should move the `_crypt` special-case into a constant + if python_major_minor == "3.13" { + wanted.remove("_crypt"); + } + if matches!(python_major_minor, "3.8" | "3.9" | "3.10" | "3.11" | "3.12") { + wanted.extend(GLOBAL_EXTENSIONS_LINUX_PRE_3_13); + } - if !is_linux_musl { + if !is_linux_musl && matches!(python_major_minor, "3.8" | "3.9" | "3.10" | "3.11" | "3.12") + { wanted.insert("ossaudiodev"); } } - if (is_linux || is_macos) && matches!(python_major_minor, "3.9" | "3.10" | "3.11" | "3.12") { + if (is_linux || is_macos) + && matches!( + python_major_minor, + "3.9" | "3.10" | "3.11" | "3.12" | "3.13" + ) + { wanted.extend([ "_testbuffer", "_testimportmultiple", @@ -1486,7 +1539,11 @@ fn validate_extension_modules( ]); } - if (is_linux || is_macos) && python_major_minor == "3.12" { + if (is_linux || is_macos) && python_major_minor == "3.13" { + wanted.extend(["_suggestions", "_testexternalinspection"]); + } + + if (is_linux || is_macos) && matches!(python_major_minor, "3.12" | "3.13") { wanted.insert("_testsinglephase"); } @@ -1500,7 +1557,7 @@ fn validate_extension_modules( } // _wmi is Windows only on 3.12+. - if python_major_minor == "3.12" && is_windows { + if matches!(python_major_minor, "3.12" | "3.13") && is_windows { wanted.insert("_wmi"); } @@ -1623,6 +1680,8 @@ fn validate_distribution( "3.11" } else if dist_filename.starts_with("cpython-3.12.") { "3.12" + } else if dist_filename.starts_with("cpython-3.13.") { + "3.13" } else { return Err(anyhow!("could not parse Python version from filename")); }; @@ -1903,9 +1962,14 @@ fn validate_distribution( // Static distributions never export symbols. let wanted = if is_static { false - // For some strange reason _PyWarnings_Init is exported as part of the ABI. + // For some strange reason _PyWarnings_Init is exported as part of the ABI } else if name == "_warnings" { - true + // But not on Python 3.13 on Windows + if triple.contains("-windows-") { + matches!(python_major_minor, "3.8" | "3.9" | "3.10" | "3.11" | "3.12") + } else { + true + } // Windows dynamic doesn't export extension module init functions. } else if triple.contains("-windows-") { false