From 131ed572a70fc8c120179cd7ddd73154f8813d05 Mon Sep 17 00:00:00 2001
From: Charlie Marsh <charlie.r.marsh@gmail.com>
Date: Sun, 15 Dec 2024 13:22:52 -0500
Subject: [PATCH 1/5] Try tkinter

---
 build-macos.py                   |   2 +-
 cpython-unix/build-cpython.sh    |   2 +
 cpython-unix/build-main.py       |   2 +-
 cpython-unix/patch-tkinter.patch | 101 +++++++++++++++++++++++++++++++
 4 files changed, 105 insertions(+), 2 deletions(-)
 create mode 100644 cpython-unix/patch-tkinter.patch

diff --git a/build-macos.py b/build-macos.py
index 0061fc13..d2d8cd84 100755
--- a/build-macos.py
+++ b/build-macos.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python3.12
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at https://mozilla.org/MPL/2.0/.
diff --git a/cpython-unix/build-cpython.sh b/cpython-unix/build-cpython.sh
index 6faf4627..074ec0c1 100755
--- a/cpython-unix/build-cpython.sh
+++ b/cpython-unix/build-cpython.sh
@@ -184,6 +184,8 @@ fi
 # See https://bugs.python.org/issue37060.
 patch -p1 -i ${ROOT}/patch-ctypes-static-binary.patch
 
+patch -p1 -i ${ROOT}/patch-tkinter.patch
+
 # Older versions of Python need patching to work with modern mpdecimal.
 if [ -n "${PYTHON_MEETS_MAXIMUM_VERSION_3_9}" ]; then
     patch -p1 -i ${ROOT}/patch-decimal-modern-mpdecimal.patch
diff --git a/cpython-unix/build-main.py b/cpython-unix/build-main.py
index 1e310b22..24d0b485 100755
--- a/cpython-unix/build-main.py
+++ b/cpython-unix/build-main.py
@@ -69,7 +69,7 @@ def main():
             "cpython-3.12",
             "cpython-3.13",
         },
-        default="cpython-3.11",
+        default="cpython-3.13",
         help="Python distribution to build",
     )
     parser.add_argument(
diff --git a/cpython-unix/patch-tkinter.patch b/cpython-unix/patch-tkinter.patch
new file mode 100644
index 00000000..f18bfac9
--- /dev/null
+++ b/cpython-unix/patch-tkinter.patch
@@ -0,0 +1,101 @@
+diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py
+index bfec04bb6c1..6f3cfba6bbf 100644
+--- a/Lib/tkinter/__init__.py
++++ b/Lib/tkinter/__init__.py
+@@ -54,6 +54,12 @@
+ _magic_re = re.compile(r'([\\{}])')
+ _space_re = re.compile(r'([\s])', re.ASCII)
+ 
++# Facilitate discovery of the Tcl/Tk libraries.
++import os
++
++os.environ['TCL_LIBRARY'] = sys.base_prefix + '/tcl/tcl' + _tkinter.TCL_VERSION
++os.environ['TK_LIBRARY'] = sys.base_prefix + '/tcl/tk' + _tkinter.TK_VERSION
++
+ 
+ def _join(value):
+     """Internal function."""
+diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c
+index 45897817a56..03652c86c1b 100644
+--- a/Modules/_tkinter.c
++++ b/Modules/_tkinter.c
+@@ -26,9 +26,8 @@ Copyright (C) 1994 Steen Lumholt.
+ #endif
+ 
+ #include "Python.h"
+-#ifdef MS_WINDOWS
+-#  include "pycore_fileutils.h"   // _Py_stat()
+-#endif
++
++#include "pycore_fileutils.h"   // _Py_stat()
+ 
+ #include "pycore_long.h"          // _PyLong_IsNegative()
+ 
+@@ -132,6 +131,7 @@ typedef int Tcl_Size;
+ #ifdef MS_WINDOWS
+ #include <conio.h>
+ #define WAIT_FOR_STDIN
++#endif
+ 
+ static PyObject *
+ _get_tcl_lib_path(void)
+@@ -149,7 +149,7 @@ _get_tcl_lib_path(void)
+         }
+ 
+         /* Check expected location for an installed Python first */
+-        tcl_library_path = PyUnicode_FromString("\\tcl\\tcl" TCL_VERSION);
++        tcl_library_path = PyUnicode_FromString("/tcl/tcl" TCL_VERSION);
+         if (tcl_library_path == NULL) {
+             return NULL;
+         }
+@@ -167,7 +167,7 @@ _get_tcl_lib_path(void)
+             errno = 0;
+ #ifdef Py_TCLTK_DIR
+             tcl_library_path = PyUnicode_FromString(
+-                                    Py_TCLTK_DIR "\\lib\\tcl" TCL_VERSION);
++                                    Py_TCLTK_DIR "/lib/tcl" TCL_VERSION);
+             if (tcl_library_path == NULL) {
+                 return NULL;
+             }
+@@ -189,7 +189,6 @@ _get_tcl_lib_path(void)
+     }
+     return tcl_library_path;
+ }
+-#endif /* MS_WINDOWS */
+ 
+ /* The threading situation is complicated.  Tcl is not thread-safe, except
+    when configured with --enable-threads.
+@@ -702,7 +701,6 @@ Tkapp_New(const char *screenName, const char *className,
+         PyMem_Free(args);
+     }
+ 
+-#ifdef MS_WINDOWS
+     {
+         PyObject *str_path;
+         PyObject *utf8_path;
+@@ -727,7 +725,6 @@ Tkapp_New(const char *screenName, const char *className,
+             }
+         }
+     }
+-#endif
+ 
+     if (Tcl_AppInit(v->interp) != TCL_OK) {
+         PyObject *result = Tkinter_Error(v);
+@@ -3520,7 +3517,6 @@ PyInit__tkinter(void)
+     if (uexe && PyUnicode_Check(uexe)) {   // sys.executable can be None
+         cexe = PyUnicode_EncodeFSDefault(uexe);
+         if (cexe) {
+-#ifdef MS_WINDOWS
+             int set_var = 0;
+             PyObject *str_path;
+             wchar_t *wcs_path;
+@@ -3551,9 +3547,6 @@ PyInit__tkinter(void)
+                 SetEnvironmentVariableW(L"TCL_LIBRARY", NULL);
+                 PyMem_Free(wcs_path);
+             }
+-#else
+-            Tcl_FindExecutable(PyBytes_AS_STRING(cexe));
+-#endif /* MS_WINDOWS */
+         }
+         Py_XDECREF(cexe);
+     }

From 1b2d826e30954e5042208be4b6318babe50d417b Mon Sep 17 00:00:00 2001
From: Charlie Marsh <charlie.r.marsh@gmail.com>
Date: Sun, 15 Dec 2024 14:37:27 -0500
Subject: [PATCH 2/5] Patch C

---
 .github/workflows/linux.yml      | 865 -------------------------------
 cpython-unix/patch-tkinter.patch | 165 +++---
 2 files changed, 92 insertions(+), 938 deletions(-)

diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml
index 8e006509..5228640b 100644
--- a/.github/workflows/linux.yml
+++ b/.github/workflows/linux.yml
@@ -120,607 +120,25 @@ jobs:
       fail-fast: false
       matrix:
         build:
-          # Cross-compiles can't do PGO.
-
-          - target_triple: 'aarch64-unknown-linux-gnu'
-            py: 'cpython-3.9'
-            options: 'debug'
-          - target_triple: 'aarch64-unknown-linux-gnu'
-            py: 'cpython-3.9'
-            options: 'noopt'
-          - target_triple: 'aarch64-unknown-linux-gnu'
-            py: 'cpython-3.9'
-            options: 'lto'
-
-          - target_triple: 'aarch64-unknown-linux-gnu'
-            py: 'cpython-3.10'
-            options: 'debug'
-          - target_triple: 'aarch64-unknown-linux-gnu'
-            py: 'cpython-3.10'
-            options: 'noopt'
-          - target_triple: 'aarch64-unknown-linux-gnu'
-            py: 'cpython-3.10'
-            options: 'lto'
-
-          - target_triple: 'aarch64-unknown-linux-gnu'
-            py: 'cpython-3.11'
-            options: 'debug'
-          - target_triple: 'aarch64-unknown-linux-gnu'
-            py: 'cpython-3.11'
-            options: 'noopt'
-          - target_triple: 'aarch64-unknown-linux-gnu'
-            py: 'cpython-3.11'
-            options: 'lto'
-
-          - target_triple: 'aarch64-unknown-linux-gnu'
-            py: 'cpython-3.12'
-            options: 'debug'
-          - target_triple: 'aarch64-unknown-linux-gnu'
-            py: 'cpython-3.12'
-            options: 'noopt'
-          - target_triple: 'aarch64-unknown-linux-gnu'
-            py: 'cpython-3.12'
-            options: 'lto'
-
-          # Cross-compiles can't do PGO and require Python 3.9.
-          - target_triple: 'armv7-unknown-linux-gnueabi'
-            py: 'cpython-3.9'
-            options: 'debug'
-          - target_triple: 'armv7-unknown-linux-gnueabi'
-            py: 'cpython-3.9'
-            options: 'noopt'
-          - target_triple: 'armv7-unknown-linux-gnueabi'
-            py: 'cpython-3.9'
-            options: 'lto'
-
-          - target_triple: 'armv7-unknown-linux-gnueabi'
-            py: 'cpython-3.10'
-            options: 'debug'
-          - target_triple: 'armv7-unknown-linux-gnueabi'
-            py: 'cpython-3.10'
-            options: 'noopt'
-          - target_triple: 'armv7-unknown-linux-gnueabi'
-            py: 'cpython-3.10'
-            options: 'lto'
-
-          - target_triple: 'armv7-unknown-linux-gnueabi'
-            py: 'cpython-3.11'
-            options: 'debug'
-          - target_triple: 'armv7-unknown-linux-gnueabi'
-            py: 'cpython-3.11'
-            options: 'noopt'
-          - target_triple: 'armv7-unknown-linux-gnueabi'
-            py: 'cpython-3.11'
-            options: 'lto'
-
-          - target_triple: 'armv7-unknown-linux-gnueabi'
-            py: 'cpython-3.12'
-            options: 'debug'
-          - target_triple: 'armv7-unknown-linux-gnueabi'
-            py: 'cpython-3.12'
-            options: 'noopt'
-          - target_triple: 'armv7-unknown-linux-gnueabi'
-            py: 'cpython-3.12'
-            options: 'lto'
-
-          # Cross-compiles can't do PGO and require Python 3.9.
-          - target_triple: 'armv7-unknown-linux-gnueabihf'
-            py: 'cpython-3.9'
-            options: 'debug'
-          - target_triple: 'armv7-unknown-linux-gnueabihf'
-            py: 'cpython-3.9'
-            options: 'noopt'
-          - target_triple: 'armv7-unknown-linux-gnueabihf'
-            py: 'cpython-3.9'
-            options: 'lto'
-
-          - target_triple: 'armv7-unknown-linux-gnueabihf'
-            py: 'cpython-3.10'
-            options: 'debug'
-          - target_triple: 'armv7-unknown-linux-gnueabihf'
-            py: 'cpython-3.10'
-            options: 'noopt'
-          - target_triple: 'armv7-unknown-linux-gnueabihf'
-            py: 'cpython-3.10'
-            options: 'lto'
-
-          - target_triple: 'armv7-unknown-linux-gnueabihf'
-            py: 'cpython-3.11'
-            options: 'debug'
-          - target_triple: 'armv7-unknown-linux-gnueabihf'
-            py: 'cpython-3.11'
-            options: 'noopt'
-          - target_triple: 'armv7-unknown-linux-gnueabihf'
-            py: 'cpython-3.11'
-            options: 'lto'
-
-          - target_triple: 'armv7-unknown-linux-gnueabihf'
-            py: 'cpython-3.12'
-            options: 'debug'
-          - target_triple: 'armv7-unknown-linux-gnueabihf'
-            py: 'cpython-3.12'
-            options: 'noopt'
-          - target_triple: 'armv7-unknown-linux-gnueabihf'
-            py: 'cpython-3.12'
-            options: 'lto'
-
-          # Cross-compiles can't do PGO and require Python 3.9.
-          - target_triple: 's390x-unknown-linux-gnu'
-            py: 'cpython-3.9'
-            options: 'debug'
-          - target_triple: 's390x-unknown-linux-gnu'
-            py: 'cpython-3.9'
-            options: 'noopt'
-          - target_triple: 's390x-unknown-linux-gnu'
-            py: 'cpython-3.9'
-            options: 'lto'
-
-          - target_triple: 's390x-unknown-linux-gnu'
-            py: 'cpython-3.10'
-            options: 'debug'
-          - target_triple: 's390x-unknown-linux-gnu'
-            py: 'cpython-3.10'
-            options: 'noopt'
-          - target_triple: 's390x-unknown-linux-gnu'
-            py: 'cpython-3.10'
-            options: 'lto'
-
-          - target_triple: 's390x-unknown-linux-gnu'
-            py: 'cpython-3.11'
-            options: 'debug'
-          - target_triple: 's390x-unknown-linux-gnu'
-            py: 'cpython-3.11'
-            options: 'noopt'
-          - target_triple: 's390x-unknown-linux-gnu'
-            py: 'cpython-3.11'
-            options: 'lto'
-
-          - target_triple: 's390x-unknown-linux-gnu'
-            py: 'cpython-3.12'
-            options: 'debug'
-          - target_triple: 's390x-unknown-linux-gnu'
-            py: 'cpython-3.12'
-            options: 'noopt'
-          - target_triple: 's390x-unknown-linux-gnu'
-            py: 'cpython-3.12'
-            options: 'lto'
-
-          # Cross-compiles can't do PGO and require Python 3.9.
-          - target_triple: 'ppc64le-unknown-linux-gnu'
-            py: 'cpython-3.9'
-            options: 'debug'
-          - target_triple: 'ppc64le-unknown-linux-gnu'
-            py: 'cpython-3.9'
-            options: 'noopt'
-          - target_triple: 'ppc64le-unknown-linux-gnu'
-            py: 'cpython-3.9'
-            options: 'lto'
-
-          - target_triple: 'ppc64le-unknown-linux-gnu'
-            py: 'cpython-3.10'
-            options: 'debug'
-          - target_triple: 'ppc64le-unknown-linux-gnu'
-            py: 'cpython-3.10'
-            options: 'noopt'
-          - target_triple: 'ppc64le-unknown-linux-gnu'
-            py: 'cpython-3.10'
-            options: 'lto'
-
-          - target_triple: 'ppc64le-unknown-linux-gnu'
-            py: 'cpython-3.11'
-            options: 'debug'
-          - target_triple: 'ppc64le-unknown-linux-gnu'
-            py: 'cpython-3.11'
-            options: 'noopt'
-          - target_triple: 'ppc64le-unknown-linux-gnu'
-            py: 'cpython-3.11'
-            options: 'lto'
-
-          - target_triple: 'ppc64le-unknown-linux-gnu'
-            py: 'cpython-3.12'
-            options: 'debug'
-          - target_triple: 'ppc64le-unknown-linux-gnu'
-            py: 'cpython-3.12'
-            options: 'noopt'
-          - target_triple: 'ppc64le-unknown-linux-gnu'
-            py: 'cpython-3.12'
-            options: 'lto'
-
           - target_triple: 'x86_64-unknown-linux-gnu'
             py: 'cpython-3.9'
             options: 'debug'
             run: true
-          - target_triple: 'x86_64-unknown-linux-gnu'
-            py: 'cpython-3.9'
-            options: 'pgo'
-            run: true
-          - target_triple: 'x86_64-unknown-linux-gnu'
-            py: 'cpython-3.9'
-            options: 'pgo+lto'
-            run: true
 
           - target_triple: 'x86_64-unknown-linux-gnu'
             py: 'cpython-3.10'
             options: 'debug'
             run: true
-          - target_triple: 'x86_64-unknown-linux-gnu'
-            py: 'cpython-3.10'
-            options: 'pgo'
-            run: true
-          - target_triple: 'x86_64-unknown-linux-gnu'
-            py: 'cpython-3.10'
-            options: 'pgo+lto'
-            run: true
 
           - target_triple: 'x86_64-unknown-linux-gnu'
             py: 'cpython-3.11'
             options: 'debug'
             run: true
-          - target_triple: 'x86_64-unknown-linux-gnu'
-            py: 'cpython-3.11'
-            options: 'pgo'
-            run: true
-          - target_triple: 'x86_64-unknown-linux-gnu'
-            py: 'cpython-3.11'
-            options: 'pgo+lto'
-            run: true
 
           - target_triple: 'x86_64-unknown-linux-gnu'
             py: 'cpython-3.12'
             options: 'debug'
             run: true
-          - target_triple: 'x86_64-unknown-linux-gnu'
-            py: 'cpython-3.12'
-            options: 'pgo'
-            run: true
-          - target_triple: 'x86_64-unknown-linux-gnu'
-            py: 'cpython-3.12'
-            options: 'pgo+lto'
-            run: true
-
-          - target_triple: 'x86_64_v2-unknown-linux-gnu'
-            py: 'cpython-3.9'
-            options: 'debug'
-            run: true
-          - target_triple: 'x86_64_v2-unknown-linux-gnu'
-            py: 'cpython-3.9'
-            options: 'pgo'
-            run: true
-          - target_triple: 'x86_64_v2-unknown-linux-gnu'
-            py: 'cpython-3.9'
-            options: 'pgo+lto'
-            run: true
-
-          - target_triple: 'x86_64_v2-unknown-linux-gnu'
-            py: 'cpython-3.10'
-            options: 'debug'
-            run: true
-          - target_triple: 'x86_64_v2-unknown-linux-gnu'
-            py: 'cpython-3.10'
-            options: 'pgo'
-            run: true
-          - target_triple: 'x86_64_v2-unknown-linux-gnu'
-            py: 'cpython-3.10'
-            options: 'pgo+lto'
-            run: true
-
-          - target_triple: 'x86_64_v2-unknown-linux-gnu'
-            py: 'cpython-3.11'
-            options: 'debug'
-            run: true
-          - target_triple: 'x86_64_v2-unknown-linux-gnu'
-            py: 'cpython-3.11'
-            options: 'pgo'
-            run: true
-          - target_triple: 'x86_64_v2-unknown-linux-gnu'
-            py: 'cpython-3.11'
-            options: 'pgo+lto'
-            run: true
-
-          - target_triple: 'x86_64_v2-unknown-linux-gnu'
-            py: 'cpython-3.12'
-            options: 'debug'
-            run: true
-          - target_triple: 'x86_64_v2-unknown-linux-gnu'
-            py: 'cpython-3.12'
-            options: 'pgo'
-            run: true
-          - target_triple: 'x86_64_v2-unknown-linux-gnu'
-            py: 'cpython-3.12'
-            options: 'pgo+lto'
-            run: true
-
-          - target_triple: 'x86_64_v3-unknown-linux-gnu'
-            py: 'cpython-3.9'
-            options: 'debug'
-            run: true
-          - target_triple: 'x86_64_v3-unknown-linux-gnu'
-            py: 'cpython-3.9'
-            options: 'pgo'
-            run: true
-          - target_triple: 'x86_64_v3-unknown-linux-gnu'
-            py: 'cpython-3.9'
-            options: 'pgo+lto'
-            run: true
-
-          - target_triple: 'x86_64_v3-unknown-linux-gnu'
-            py: 'cpython-3.10'
-            options: 'debug'
-            run: true
-          - target_triple: 'x86_64_v3-unknown-linux-gnu'
-            py: 'cpython-3.10'
-            options: 'pgo'
-            run: true
-          - target_triple: 'x86_64_v3-unknown-linux-gnu'
-            py: 'cpython-3.10'
-            options: 'pgo+lto'
-            run: true
-
-          - target_triple: 'x86_64_v3-unknown-linux-gnu'
-            py: 'cpython-3.11'
-            options: 'debug'
-            run: true
-          - target_triple: 'x86_64_v3-unknown-linux-gnu'
-            py: 'cpython-3.11'
-            options: 'pgo'
-            run: true
-          - target_triple: 'x86_64_v3-unknown-linux-gnu'
-            py: 'cpython-3.11'
-            options: 'pgo+lto'
-            run: true
-
-          - target_triple: 'x86_64_v3-unknown-linux-gnu'
-            py: 'cpython-3.12'
-            options: 'debug'
-            run: true
-          - target_triple: 'x86_64_v3-unknown-linux-gnu'
-            py: 'cpython-3.12'
-            options: 'pgo'
-            run: true
-          - target_triple: 'x86_64_v3-unknown-linux-gnu'
-            py: 'cpython-3.12'
-            options: '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'
-            options: 'debug'
-          - target_triple: 'x86_64_v4-unknown-linux-gnu'
-            py: 'cpython-3.9'
-            options: 'noopt'
-          - target_triple: 'x86_64_v4-unknown-linux-gnu'
-            py: 'cpython-3.9'
-            options: 'lto'
-
-          # 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.10'
-            options: 'debug'
-          - target_triple: 'x86_64_v4-unknown-linux-gnu'
-            py: 'cpython-3.10'
-            options: 'noopt'
-          - target_triple: 'x86_64_v4-unknown-linux-gnu'
-            py: 'cpython-3.10'
-            options: 'lto'
-
-          - target_triple: 'x86_64_v4-unknown-linux-gnu'
-            py: 'cpython-3.11'
-            options: 'debug'
-          - target_triple: 'x86_64_v4-unknown-linux-gnu'
-            py: 'cpython-3.11'
-            options: 'noopt'
-          - target_triple: 'x86_64_v4-unknown-linux-gnu'
-            py: 'cpython-3.11'
-            options: 'lto'
-
-          - target_triple: 'x86_64_v4-unknown-linux-gnu'
-            py: 'cpython-3.12'
-            options: 'debug'
-          - target_triple: 'x86_64_v4-unknown-linux-gnu'
-            py: 'cpython-3.12'
-            options: 'noopt'
-          - target_triple: 'x86_64_v4-unknown-linux-gnu'
-            py: 'cpython-3.12'
-            options: 'lto'
-
-          # musl doesn't support PGO.
-
-          - target_triple: 'x86_64-unknown-linux-musl'
-            py: 'cpython-3.9'
-            options: 'debug'
-            run: true
-          - target_triple: 'x86_64-unknown-linux-musl'
-            py: 'cpython-3.9'
-            options: 'noopt'
-            run: true
-          - target_triple: 'x86_64-unknown-linux-musl'
-            py: 'cpython-3.9'
-            options: 'lto'
-            run: true
-
-          - target_triple: 'x86_64-unknown-linux-musl'
-            py: 'cpython-3.10'
-            options: 'debug'
-            run: true
-          - target_triple: 'x86_64-unknown-linux-musl'
-            py: 'cpython-3.10'
-            options: 'noopt'
-            run: true
-          - target_triple: 'x86_64-unknown-linux-musl'
-            py: 'cpython-3.10'
-            options: 'lto'
-            run: true
-
-          - target_triple: 'x86_64-unknown-linux-musl'
-            py: 'cpython-3.11'
-            options: 'debug'
-            run: true
-          - target_triple: 'x86_64-unknown-linux-musl'
-            py: 'cpython-3.11'
-            options: 'noopt'
-            run: true
-          - target_triple: 'x86_64-unknown-linux-musl'
-            py: 'cpython-3.11'
-            options: 'lto'
-            run: true
-
-          - target_triple: 'x86_64-unknown-linux-musl'
-            py: 'cpython-3.12'
-            options: 'debug'
-            run: true
-          - target_triple: 'x86_64-unknown-linux-musl'
-            py: 'cpython-3.12'
-            options: 'noopt'
-            run: true
-          - target_triple: 'x86_64-unknown-linux-musl'
-            py: 'cpython-3.12'
-            options: 'lto'
-            run: true
-
-          - target_triple: 'x86_64_v2-unknown-linux-musl'
-            py: 'cpython-3.9'
-            options: 'debug'
-            run: true
-          - target_triple: 'x86_64_v2-unknown-linux-musl'
-            py: 'cpython-3.9'
-            options: 'noopt'
-            run: true
-          - target_triple: 'x86_64_v2-unknown-linux-musl'
-            py: 'cpython-3.9'
-            options: 'lto'
-            run: true
-
-          - target_triple: 'x86_64_v2-unknown-linux-musl'
-            py: 'cpython-3.10'
-            options: 'debug'
-            run: true
-          - target_triple: 'x86_64_v2-unknown-linux-musl'
-            py: 'cpython-3.10'
-            options: 'noopt'
-            run: true
-          - target_triple: 'x86_64_v2-unknown-linux-musl'
-            py: 'cpython-3.10'
-            options: 'lto'
-            run: true
-
-          - target_triple: 'x86_64_v2-unknown-linux-musl'
-            py: 'cpython-3.11'
-            options: 'debug'
-            run: true
-          - target_triple: 'x86_64_v2-unknown-linux-musl'
-            py: 'cpython-3.11'
-            options: 'noopt'
-            run: true
-          - target_triple: 'x86_64_v2-unknown-linux-musl'
-            py: 'cpython-3.11'
-            options: 'lto'
-            run: true
-
-          - target_triple: 'x86_64_v2-unknown-linux-musl'
-            py: 'cpython-3.12'
-            options: 'debug'
-            run: true
-          - target_triple: 'x86_64_v2-unknown-linux-musl'
-            py: 'cpython-3.12'
-            options: 'noopt'
-            run: true
-          - target_triple: 'x86_64_v2-unknown-linux-musl'
-            py: 'cpython-3.12'
-            options: 'lto'
-            run: true
-
-          - target_triple: 'x86_64_v3-unknown-linux-musl'
-            py: 'cpython-3.9'
-            options: 'debug'
-            run: true
-          - target_triple: 'x86_64_v3-unknown-linux-musl'
-            py: 'cpython-3.9'
-            options: 'noopt'
-            run: true
-          - target_triple: 'x86_64_v3-unknown-linux-musl'
-            py: 'cpython-3.9'
-            options: 'lto'
-            run: true
-
-          - target_triple: 'x86_64_v3-unknown-linux-musl'
-            py: 'cpython-3.10'
-            options: 'debug'
-            run: true
-          - target_triple: 'x86_64_v3-unknown-linux-musl'
-            py: 'cpython-3.10'
-            options: 'noopt'
-            run: true
-          - target_triple: 'x86_64_v3-unknown-linux-musl'
-            py: 'cpython-3.10'
-            options: 'lto'
-            run: true
-
-          - target_triple: 'x86_64_v3-unknown-linux-musl'
-            py: 'cpython-3.11'
-            options: 'debug'
-            run: true
-          - target_triple: 'x86_64_v3-unknown-linux-musl'
-            py: 'cpython-3.11'
-            options: 'noopt'
-            run: true
-          - target_triple: 'x86_64_v3-unknown-linux-musl'
-            py: 'cpython-3.11'
-            options: 'lto'
-            run: true
-
-          - target_triple: 'x86_64_v3-unknown-linux-musl'
-            py: 'cpython-3.12'
-            options: 'debug'
-            run: true
-          - target_triple: 'x86_64_v3-unknown-linux-musl'
-            py: 'cpython-3.12'
-            options: 'noopt'
-            run: true
-          - target_triple: 'x86_64_v3-unknown-linux-musl'
-            py: 'cpython-3.12'
-            options: 'lto'
-            run: true
-
-          - target_triple: 'x86_64_v4-unknown-linux-musl'
-            py: 'cpython-3.9'
-            options: 'debug'
-          - target_triple: 'x86_64_v4-unknown-linux-musl'
-            py: 'cpython-3.9'
-            options: 'noopt'
-          - target_triple: 'x86_64_v4-unknown-linux-musl'
-            py: 'cpython-3.9'
-            options: 'lto'
-
-          - target_triple: 'x86_64_v4-unknown-linux-musl'
-            py: 'cpython-3.10'
-            options: 'debug'
-          - target_triple: 'x86_64_v4-unknown-linux-musl'
-            py: 'cpython-3.10'
-            options: 'noopt'
-          - target_triple: 'x86_64_v4-unknown-linux-musl'
-            py: 'cpython-3.10'
-            options: 'lto'
-
-          - target_triple: 'x86_64_v4-unknown-linux-musl'
-            py: 'cpython-3.11'
-            options: 'debug'
-          - target_triple: 'x86_64_v4-unknown-linux-musl'
-            py: 'cpython-3.11'
-            options: 'noopt'
-          - target_triple: 'x86_64_v4-unknown-linux-musl'
-            py: 'cpython-3.11'
-            options: 'lto'
-
-          - target_triple: 'x86_64_v4-unknown-linux-musl'
-            py: 'cpython-3.12'
-            options: 'debug'
-          - target_triple: 'x86_64_v4-unknown-linux-musl'
-            py: 'cpython-3.12'
-            options: 'noopt'
-          - target_triple: 'x86_64_v4-unknown-linux-musl'
-            py: 'cpython-3.12'
-            options: 'lto'
 
     needs:
       - pythonbuild
@@ -796,293 +214,10 @@ jobs:
       fail-fast: false
       matrix:
         build:
-
-          - target_triple: 'aarch64-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'debug'
-          - target_triple: 'aarch64-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'noopt'
-          - target_triple: 'aarch64-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'lto'
-          - target_triple: 'aarch64-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'freethreaded+debug'
-          - target_triple: 'aarch64-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'freethreaded+noopt'
-          - target_triple: 'aarch64-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'freethreaded+lto'
-
-          - target_triple: 'armv7-unknown-linux-gnueabi'
-            py: 'cpython-3.13'
-            options: 'debug'
-          - target_triple: 'armv7-unknown-linux-gnueabi'
-            py: 'cpython-3.13'
-            options: 'noopt'
-          - target_triple: 'armv7-unknown-linux-gnueabi'
-            py: 'cpython-3.13'
-            options: 'lto'
-          - target_triple: 'armv7-unknown-linux-gnueabi'
-            py: 'cpython-3.13'
-            options: 'freethreaded+debug'
-          - target_triple: 'armv7-unknown-linux-gnueabi'
-            py: 'cpython-3.13'
-            options: 'freethreaded+noopt'
-          - target_triple: 'armv7-unknown-linux-gnueabi'
-            py: 'cpython-3.13'
-            options: 'freethreaded+lto'
-
-          - target_triple: 'armv7-unknown-linux-gnueabihf'
-            py: 'cpython-3.13'
-            options: 'debug'
-          - target_triple: 'armv7-unknown-linux-gnueabihf'
-            py: 'cpython-3.13'
-            options: 'noopt'
-          - target_triple: 'armv7-unknown-linux-gnueabihf'
-            py: 'cpython-3.13'
-            options: 'lto'
-          - target_triple: 'armv7-unknown-linux-gnueabihf'
-            py: 'cpython-3.13'
-            options: 'freethreaded+debug'
-          - target_triple: 'armv7-unknown-linux-gnueabihf'
-            py: 'cpython-3.13'
-            options: 'freethreaded+noopt'
-          - target_triple: 'armv7-unknown-linux-gnueabihf'
-            py: 'cpython-3.13'
-            options: 'freethreaded+lto'
-
-          - target_triple: 's390x-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'debug'
-          - target_triple: 's390x-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'noopt'
-          - target_triple: 's390x-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'lto'
-          - target_triple: 's390x-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'freethreaded+debug'
-          - target_triple: 's390x-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'freethreaded+noopt'
-          - target_triple: 's390x-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'freethreaded+lto'
-
-          - target_triple: 'ppc64le-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'debug'
-          - target_triple: 'ppc64le-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'noopt'
-          - target_triple: 'ppc64le-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'lto'
-          - target_triple: 'ppc64le-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'freethreaded+debug'
-          - target_triple: 'ppc64le-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'freethreaded+noopt'
-          - target_triple: 'ppc64le-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'freethreaded+lto'
-
-          - target_triple: 'x86_64-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'debug'
-            run: true
-          - target_triple: 'x86_64-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'pgo'
-            run: true
-          - target_triple: 'x86_64-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'pgo+lto'
-            run: true
-          - target_triple: 'x86_64-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'freethreaded+debug'
-            run: true
           - target_triple: 'x86_64-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'freethreaded+pgo'
-            run: true
-          - target_triple: 'x86_64-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'freethreaded+pgo+lto'
-            run: true
-
-          - target_triple: 'x86_64_v2-unknown-linux-gnu'
             py: 'cpython-3.13'
             options: 'debug'
             run: true
-          - target_triple: 'x86_64_v2-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'pgo'
-            run: true
-          - target_triple: 'x86_64_v2-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'pgo+lto'
-            run: true
-          - target_triple: 'x86_64_v2-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'freethreaded+debug'
-            run: true
-          - target_triple: 'x86_64_v2-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'freethreaded+pgo'
-            run: true
-          - target_triple: 'x86_64_v2-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'freethreaded+pgo+lto'
-            run: true
-
-          - target_triple: 'x86_64_v3-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'debug'
-            run: true
-          - target_triple: 'x86_64_v3-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'pgo'
-            run: true
-          - target_triple: 'x86_64_v3-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'pgo+lto'
-            run: true
-          - target_triple: 'x86_64_v3-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'freethreaded+debug'
-            run: true
-          - target_triple: 'x86_64_v3-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'freethreaded+pgo'
-            run: true
-          - target_triple: 'x86_64_v3-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'freethreaded+pgo+lto'
-            run: true
-
-          - target_triple: 'x86_64-unknown-linux-musl'
-            py: 'cpython-3.13'
-            options: 'debug'
-            run: true
-          - target_triple: 'x86_64-unknown-linux-musl'
-            py: 'cpython-3.13'
-            options: 'noopt'
-            run: true
-          - target_triple: 'x86_64-unknown-linux-musl'
-            py: 'cpython-3.13'
-            options: 'lto'
-            run: true
-          # TODO: Free-threaded musl builds are blocked by upgrading LLVM 14 -> 18.
-          # - target_triple: 'x86_64-unknown-linux-musl'
-          #   py: 'cpython-3.13'
-          #   options: 'freethreaded+debug'
-          #   run: true
-          # - target_triple: 'x86_64-unknown-linux-musl'
-          #   py: 'cpython-3.13'
-          #   options: 'freethreaded+noopt'
-          #   run: true
-          # - target_triple: 'x86_64-unknown-linux-musl'
-          #   py: 'cpython-3.13'
-          #   options: 'freethreaded+lto'
-          #   run: true
-
-          - target_triple: 'x86_64_v2-unknown-linux-musl'
-            py: 'cpython-3.13'
-            options: 'debug'
-            run: true
-          - target_triple: 'x86_64_v2-unknown-linux-musl'
-            py: 'cpython-3.13'
-            options: 'noopt'
-            run: true
-          - target_triple: 'x86_64_v2-unknown-linux-musl'
-            py: 'cpython-3.13'
-            options: 'lto'
-            run: true
-          # TODO: Free-threaded musl builds are blocked by upgrading LLVM 14 -> 18.
-          # - target_triple: 'x86_64_v2-unknown-linux-musl'
-          #   py: 'cpython-3.13'
-          #   options: 'freethreaded+debug'
-          #   run: true
-          # - target_triple: 'x86_64_v2-unknown-linux-musl'
-          #   py: 'cpython-3.13'
-          #   options: 'freethreaded+noopt'
-          #   run: true
-          # - target_triple: 'x86_64_v2-unknown-linux-musl'
-          #   py: 'cpython-3.13'
-          #   options: 'freethreaded+lto'
-          #   run: true
-
-          - target_triple: 'x86_64_v4-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'debug'
-          - target_triple: 'x86_64_v4-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'noopt'
-          - target_triple: 'x86_64_v4-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'lto'
-          - target_triple: 'x86_64_v4-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'freethreaded+debug'
-          - target_triple: 'x86_64_v4-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'freethreaded+noopt'
-          - target_triple: 'x86_64_v4-unknown-linux-gnu'
-            py: 'cpython-3.13'
-            options: 'freethreaded+lto'
-
-          - target_triple: 'x86_64_v3-unknown-linux-musl'
-            py: 'cpython-3.13'
-            options: 'debug'
-            run: true
-          - target_triple: 'x86_64_v3-unknown-linux-musl'
-            py: 'cpython-3.13'
-            options: 'noopt'
-            run: true
-          - target_triple: 'x86_64_v3-unknown-linux-musl'
-            py: 'cpython-3.13'
-            options: 'lto'
-            run: true
-          # TODO: Free-threaded musl builds are blocked by upgrading LLVM 14 -> 18.
-          # - target_triple: 'x86_64_v3-unknown-linux-musl'
-          #   py: 'cpython-3.13'
-          #   options: 'freethreaded+debug'
-          #   run: true
-          # - target_triple: 'x86_64_v3-unknown-linux-musl'
-          #   py: 'cpython-3.13'
-          #   options: 'freethreaded+noopt'
-          #   run: true
-          # - target_triple: 'x86_64_v3-unknown-linux-musl'
-          #   py: 'cpython-3.13'
-          #   options: 'freethreaded+lto'
-          #   run: true
-
-          - target_triple: 'x86_64_v4-unknown-linux-musl'
-            py: 'cpython-3.13'
-            options: 'debug'
-          - target_triple: 'x86_64_v4-unknown-linux-musl'
-            py: 'cpython-3.13'
-            options: 'noopt'
-          - target_triple: 'x86_64_v4-unknown-linux-musl'
-            py: 'cpython-3.13'
-            options: 'lto'
-          # TODO: Free-threaded musl builds are blocked by upgrading LLVM 14 -> 18.
-          # - target_triple: 'x86_64_v4-unknown-linux-musl'
-          #   py: 'cpython-3.13'
-          #   options: 'freethreaded+debug'
-          # - target_triple: 'x86_64_v4-unknown-linux-musl'
-          #   py: 'cpython-3.13'
-          #   options: 'freethreaded+noopt'
-          # - target_triple: 'x86_64_v4-unknown-linux-musl'
-          #   py: 'cpython-3.13'
-          #   options: 'freethreaded+lto'
 
     needs:
       - pythonbuild
diff --git a/cpython-unix/patch-tkinter.patch b/cpython-unix/patch-tkinter.patch
index f18bfac9..dd818936 100644
--- a/cpython-unix/patch-tkinter.patch
+++ b/cpython-unix/patch-tkinter.patch
@@ -1,37 +1,8 @@
-diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py
-index bfec04bb6c1..6f3cfba6bbf 100644
---- a/Lib/tkinter/__init__.py
-+++ b/Lib/tkinter/__init__.py
-@@ -54,6 +54,12 @@
- _magic_re = re.compile(r'([\\{}])')
- _space_re = re.compile(r'([\s])', re.ASCII)
- 
-+# Facilitate discovery of the Tcl/Tk libraries.
-+import os
-+
-+os.environ['TCL_LIBRARY'] = sys.base_prefix + '/tcl/tcl' + _tkinter.TCL_VERSION
-+os.environ['TK_LIBRARY'] = sys.base_prefix + '/tcl/tk' + _tkinter.TK_VERSION
-+
- 
- def _join(value):
-     """Internal function."""
 diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c
-index 45897817a56..03652c86c1b 100644
+index 45897817a56..c18808e10c7 100644
 --- a/Modules/_tkinter.c
 +++ b/Modules/_tkinter.c
-@@ -26,9 +26,8 @@ Copyright (C) 1994 Steen Lumholt.
- #endif
- 
- #include "Python.h"
--#ifdef MS_WINDOWS
--#  include "pycore_fileutils.h"   // _Py_stat()
--#endif
-+
-+#include "pycore_fileutils.h"   // _Py_stat()
- 
- #include "pycore_long.h"          // _PyLong_IsNegative()
- 
-@@ -132,6 +131,7 @@ typedef int Tcl_Size;
+@@ -132,6 +132,7 @@ typedef int Tcl_Size;
  #ifdef MS_WINDOWS
  #include <conio.h>
  #define WAIT_FOR_STDIN
@@ -39,25 +10,40 @@ index 45897817a56..03652c86c1b 100644
  
  static PyObject *
  _get_tcl_lib_path(void)
-@@ -149,7 +149,7 @@ _get_tcl_lib_path(void)
+@@ -148,6 +149,7 @@ _get_tcl_lib_path(void)
+             return NULL;
          }
  
++#ifdef MS_WINDOWS
          /* Check expected location for an installed Python first */
--        tcl_library_path = PyUnicode_FromString("\\tcl\\tcl" TCL_VERSION);
-+        tcl_library_path = PyUnicode_FromString("/tcl/tcl" TCL_VERSION);
+         tcl_library_path = PyUnicode_FromString("\\tcl\\tcl" TCL_VERSION);
          if (tcl_library_path == NULL) {
-             return NULL;
+@@ -185,11 +187,31 @@ _get_tcl_lib_path(void)
+             tcl_library_path = NULL;
+ #endif
          }
-@@ -167,7 +167,7 @@ _get_tcl_lib_path(void)
-             errno = 0;
- #ifdef Py_TCLTK_DIR
-             tcl_library_path = PyUnicode_FromString(
--                                    Py_TCLTK_DIR "\\lib\\tcl" TCL_VERSION);
-+                                    Py_TCLTK_DIR "/lib/tcl" TCL_VERSION);
-             if (tcl_library_path == NULL) {
-                 return NULL;
-             }
-@@ -189,7 +189,6 @@ _get_tcl_lib_path(void)
++#else
++        /* Unix - check expected location for an installed Python */
++        tcl_library_path = PyUnicode_FromString("/lib/tcl" TCL_VERSION);
++        if (tcl_library_path == NULL) {
++            return NULL;
++        }
++        tcl_library_path = PyUnicode_Concat(prefix, tcl_library_path);
++        if (tcl_library_path == NULL) {
++            return NULL;
++        }
++        stat_return_value = _Py_stat(tcl_library_path, &stat_buf);
++        if (stat_return_value == -2) {
++            return NULL;
++        }
++        if (stat_return_value == -1) {
++            /* install location doesn't exist, reset errno and leave Tcl
++               to its own devices */
++            errno = 0;
++            tcl_library_path = NULL;
++        }
++#endif
+         already_checked = 1;
      }
      return tcl_library_path;
  }
@@ -65,37 +51,70 @@ index 45897817a56..03652c86c1b 100644
  
  /* The threading situation is complicated.  Tcl is not thread-safe, except
     when configured with --enable-threads.
-@@ -702,7 +701,6 @@ Tkapp_New(const char *screenName, const char *className,
-         PyMem_Free(args);
-     }
+@@ -710,6 +732,30 @@ Tkapp_New(const char *screenName, const char *className,
  
--#ifdef MS_WINDOWS
-     {
-         PyObject *str_path;
-         PyObject *utf8_path;
-@@ -727,7 +725,6 @@ Tkapp_New(const char *screenName, const char *className,
-             }
-         }
-     }
--#endif
+         ret = GetEnvironmentVariableW(L"TCL_LIBRARY", NULL, 0);
+         if (!ret && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
++            str_path = _get_tcl_lib_path();
++            if (str_path == NULL && PyErr_Occurred()) {
++                return NULL;
++            }
++            if (str_path != NULL) {
++                utf8_path = PyUnicode_AsUTF8String(str_path);
++                if (utf8_path == NULL) {
++                    return NULL;
++                }
++                Tcl_SetVar(v->interp,
++                           "tcl_library",
++                           PyBytes_AS_STRING(utf8_path),
++                           TCL_GLOBAL_ONLY);
++                Py_DECREF(utf8_path);
++            }
++        }
++    }
++#else
++    {
++        const char *env_val = getenv("TCL_LIBRARY");
++        if (!env_val) {
++            PyObject *str_path;
++            PyObject *utf8_path;
++
+             str_path = _get_tcl_lib_path();
+             if (str_path == NULL && PyErr_Occurred()) {
+                 return NULL;
+@@ -740,7 +786,6 @@ Tkapp_New(const char *screenName, const char *className,
+     return v;
+ }
  
-     if (Tcl_AppInit(v->interp) != TCL_OK) {
-         PyObject *result = Tkinter_Error(v);
-@@ -3520,7 +3517,6 @@ PyInit__tkinter(void)
-     if (uexe && PyUnicode_Check(uexe)) {   // sys.executable can be None
-         cexe = PyUnicode_EncodeFSDefault(uexe);
-         if (cexe) {
--#ifdef MS_WINDOWS
-             int set_var = 0;
-             PyObject *str_path;
-             wchar_t *wcs_path;
-@@ -3551,9 +3547,6 @@ PyInit__tkinter(void)
-                 SetEnvironmentVariableW(L"TCL_LIBRARY", NULL);
+-
+ static void
+ Tkapp_ThreadSend(TkappObject *self, Tcl_Event *ev,
+                  Tcl_Condition *cond, Tcl_Mutex *mutex)
+@@ -3552,7 +3597,27 @@ PyInit__tkinter(void)
                  PyMem_Free(wcs_path);
              }
--#else
--            Tcl_FindExecutable(PyBytes_AS_STRING(cexe));
--#endif /* MS_WINDOWS */
+ #else
++            int set_var = 0;
++            PyObject *str_path;
++            char *path;
++
++            if (!getenv("TCL_LIBRARY")) {
++                str_path = _get_tcl_lib_path();
++                if (str_path == NULL && PyErr_Occurred()) {
++                    Py_DECREF(m);
++                    return NULL;
++                }
++                if (str_path != NULL) {
++                    setenv("TCL_LIBRARY", path, 1);
++                    set_var = 1;
++                }
++            }
++
+             Tcl_FindExecutable(PyBytes_AS_STRING(cexe));
++
++            if (set_var) {
++                unsetenv("TCL_LIBRARY");
++            }
+ #endif /* MS_WINDOWS */
          }
          Py_XDECREF(cexe);
-     }

From 6b5f26f876e6befde12995653bfad8115eb2350e Mon Sep 17 00:00:00 2001
From: Charlie Marsh <charlie.r.marsh@gmail.com>
Date: Sun, 15 Dec 2024 14:37:39 -0500
Subject: [PATCH 3/5] Revert

---
 .github/workflows/apple.yml                   | 253 ------------------
 .github/workflows/windows.yml                 | 110 --------
 build-macos.py                                |   2 +-
 cpython-unix/build-cpython.sh                 |  11 +-
 cpython-unix/build-main.py                    |   2 +-
 ...tkinter.patch => patch-tkinter-3.13.patch} |  35 ++-
 6 files changed, 32 insertions(+), 381 deletions(-)
 delete mode 100644 .github/workflows/apple.yml
 delete mode 100644 .github/workflows/windows.yml
 rename cpython-unix/{patch-tkinter.patch => patch-tkinter-3.13.patch} (82%)

diff --git a/.github/workflows/apple.yml b/.github/workflows/apple.yml
deleted file mode 100644
index f20bc3c4..00000000
--- a/.github/workflows/apple.yml
+++ /dev/null
@@ -1,253 +0,0 @@
-name: MacOS Python build
-
-on:
-  push:
-    branches: [main]
-  pull_request:
-
-concurrency:
-  group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.sha }}
-  cancel-in-progress: ${{ github.event_name == 'pull_request' }}
-
-env:
-  FORCE_COLOR: 1
-
-jobs:
-  pythonbuild:
-    runs-on: 'macos-13'
-    steps:
-      - uses: actions/checkout@v4
-
-      - name: Emit rustc version
-        run: |
-          rustc --version > .rustc-version
-
-      - uses: actions/cache@v4
-        with:
-          path: |
-            ~/.cargo/registry
-            ~/.cargo/git
-            target
-          key: ${{ runner.os }}-pythonbuild-${{ hashFiles('Cargo.lock', '.rustc-version') }}
-
-      - name: Build
-        run: |
-          cargo build --release
-
-      - name: Upload pythonbuild Executable
-        uses: actions/upload-artifact@v4
-        with:
-          name: pythonbuild
-          path: target/release/pythonbuild
-
-  build:
-    strategy:
-      fail-fast: false
-      matrix:
-        build:
-          - target_triple: 'aarch64-apple-darwin'
-            runner: macos-14
-            py: 'cpython-3.9'
-            options: 'debug'
-          - target_triple: 'aarch64-apple-darwin'
-            runner: macos-14
-            py: 'cpython-3.9'
-            options: 'pgo'
-          - target_triple: 'aarch64-apple-darwin'
-            runner: macos-14
-            py: 'cpython-3.9'
-            options: 'pgo+lto'
-
-          - target_triple: 'aarch64-apple-darwin'
-            runner: macos-14
-            py: 'cpython-3.10'
-            options: 'debug'
-          - target_triple: 'aarch64-apple-darwin'
-            runner: macos-14
-            py: 'cpython-3.10'
-            options: 'pgo'
-          - target_triple: 'aarch64-apple-darwin'
-            runner: macos-14
-            py: 'cpython-3.10'
-            options: 'pgo+lto'
-
-          - target_triple: 'aarch64-apple-darwin'
-            runner: macos-14
-            py: 'cpython-3.11'
-            options: 'debug'
-          - target_triple: 'aarch64-apple-darwin'
-            runner: macos-14
-            py: 'cpython-3.11'
-            options: 'pgo'
-          - target_triple: 'aarch64-apple-darwin'
-            runner: macos-14
-            py: 'cpython-3.11'
-            options: 'pgo+lto'
-
-          - target_triple: 'aarch64-apple-darwin'
-            runner: macos-14
-            py: 'cpython-3.12'
-            options: 'debug'
-          - target_triple: 'aarch64-apple-darwin'
-            runner: macos-14
-            py: 'cpython-3.12'
-            options: 'pgo'
-          - target_triple: 'aarch64-apple-darwin'
-            runner: macos-14
-            py: 'cpython-3.12'
-            options: 'pgo+lto'
-
-          - target_triple: 'aarch64-apple-darwin'
-            runner: macos-14
-            py: 'cpython-3.13'
-            options: 'debug'
-          - target_triple: 'aarch64-apple-darwin'
-            runner: macos-14
-            py: 'cpython-3.13'
-            options: 'pgo'
-          - target_triple: 'aarch64-apple-darwin'
-            runner: macos-14
-            py: 'cpython-3.13'
-            options: 'pgo+lto'
-
-          - target_triple: 'aarch64-apple-darwin'
-            runner: macos-14
-            py: 'cpython-3.13'
-            options: 'freethreaded+debug'
-          - target_triple: 'aarch64-apple-darwin'
-            runner: macos-14
-            py: 'cpython-3.13'
-            options: 'freethreaded+pgo'
-          - target_triple: 'aarch64-apple-darwin'
-            runner: macos-14
-            py: 'cpython-3.13'
-            options: 'freethreaded+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.
-          - target_triple: 'x86_64-apple-darwin'
-            runner: macos-13
-            py: 'cpython-3.9'
-            options: 'debug'
-          - target_triple: 'x86_64-apple-darwin'
-            runner: macos-13
-            py: 'cpython-3.9'
-            options: 'pgo'
-          - target_triple: 'x86_64-apple-darwin'
-            runner: macos-13
-            py: 'cpython-3.9'
-            options: 'pgo+lto'
-
-          - target_triple: 'x86_64-apple-darwin'
-            runner: macos-13
-            py: 'cpython-3.10'
-            options: 'debug'
-          - target_triple: 'x86_64-apple-darwin'
-            runner: macos-13
-            py: 'cpython-3.10'
-            options: 'pgo'
-          - target_triple: 'x86_64-apple-darwin'
-            runner: macos-13
-            py: 'cpython-3.10'
-            options: 'pgo+lto'
-
-          - target_triple: 'x86_64-apple-darwin'
-            runner: macos-13
-            py: 'cpython-3.11'
-            options: 'debug'
-          - target_triple: 'x86_64-apple-darwin'
-            runner: macos-13
-            py: 'cpython-3.11'
-            options: 'pgo'
-          - target_triple: 'x86_64-apple-darwin'
-            runner: macos-13
-            py: 'cpython-3.11'
-            options: 'pgo+lto'
-
-          - target_triple: 'x86_64-apple-darwin'
-            runner: macos-13
-            py: 'cpython-3.12'
-            options: 'debug'
-          - target_triple: 'x86_64-apple-darwin'
-            runner: macos-13
-            py: 'cpython-3.12'
-            options: 'pgo'
-          - target_triple: 'x86_64-apple-darwin'
-            runner: macos-13
-            py: 'cpython-3.12'
-            options: 'pgo+lto'
-
-          - target_triple: 'x86_64-apple-darwin'
-            runner: macos-13
-            py: 'cpython-3.13'
-            options: 'debug'
-          - target_triple: 'x86_64-apple-darwin'
-            runner: macos-13
-            py: 'cpython-3.13'
-            options: 'pgo'
-          - target_triple: 'x86_64-apple-darwin'
-            runner: macos-13
-            py: 'cpython-3.13'
-            options: 'pgo+lto'
-          - target_triple: 'x86_64-apple-darwin'
-            runner: macos-13
-            py: 'cpython-3.13'
-            options: 'freethreaded+debug'
-          - target_triple: 'x86_64-apple-darwin'
-            runner: macos-13
-            py: 'cpython-3.13'
-            options: 'freethreaded+pgo'
-          - target_triple: 'x86_64-apple-darwin'
-            runner: macos-13
-            py: 'cpython-3.13'
-            options: 'freethreaded+pgo+lto'
-    needs:
-      - pythonbuild
-    runs-on: ${{ matrix.build.runner }}
-    steps:
-      - uses: actions/checkout@v4
-        with:
-          fetch-depth: 0
-
-      - name: Install Python
-        uses: actions/setup-python@v5
-        with:
-          python-version: '3.11'
-
-      - name: Download pythonbuild
-        uses: actions/download-artifact@v4
-        with:
-          name: pythonbuild
-          path: build
-
-      - name: Build
-        run: |
-          if [ "${{ matrix.build.target_triple }}" = "aarch64-apple-darwin" ]; then
-            export APPLE_SDK_PATH=/Applications/Xcode_15.2.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.2.sdk
-          elif [ "${{ matrix.build.target_triple }}" = "x86_64-apple-darwin" ]; then
-            export APPLE_SDK_PATH=/Applications/Xcode_15.2.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.2.sdk
-          else
-            echo "unhandled target triple: ${{ matrix.build.target_triple }}"
-            exit 1
-          fi
-
-          ./build-macos.py --target-triple ${{ matrix.build.target_triple }} --python ${{ matrix.build.py }} --options ${{ matrix.build.options }}
-
-      - name: Upload Distributions
-        uses: actions/upload-artifact@v4
-        with:
-          name: ${{ matrix.build.py }}-${{ matrix.build.target_triple }}-${{ matrix.build.options }}
-          path: dist/*
-
-      - uses: actions/checkout@v4
-        with:
-          repository: 'phracker/MacOSX-SDKs'
-          ref: master
-          path: macosx-sdks
-
-      - name: Validate Distribution
-        run: |
-          chmod +x build/pythonbuild
-
-          build/pythonbuild validate-distribution --macos-sdks-path macosx-sdks --run dist/*.tar.zst
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
deleted file mode 100644
index 18b83895..00000000
--- a/.github/workflows/windows.yml
+++ /dev/null
@@ -1,110 +0,0 @@
-name: Windows Python build
-
-on:
-  push:
-    branches: [main]
-  pull_request:
-
-concurrency:
-  group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.sha }}
-  cancel-in-progress: ${{ github.event_name == 'pull_request' }}
-
-env:
-  FORCE_COLOR: 1
-
-jobs:
-  pythonbuild:
-    runs-on: 'windows-2022'
-    steps:
-      - uses: actions/checkout@v4
-
-      - name: Emit rustc version
-        run: |
-          rustc --version > .rustc-version
-
-      - uses: actions/cache@v4
-        with:
-          path: |
-            C:/Rust/.cargo/registry
-            C:/Rust/.cargo/git
-            target
-          key: ${{ runner.os }}-pythonbuild-${{ hashFiles('Cargo.lock', '.rustc-version') }}
-
-      - name: Build
-        run: |
-          cargo build --release
-
-      - name: Upload executable
-        uses: actions/upload-artifact@v4
-        with:
-          name: pythonbuild
-          path: target/release/pythonbuild.exe
-
-  build:
-    strategy:
-      fail-fast: false
-      matrix:
-        py:
-          - 'cpython-3.9'
-          - 'cpython-3.10'
-          - 'cpython-3.11'
-          - 'cpython-3.12'
-          - 'cpython-3.13'
-        vcvars:
-          - 'vcvars32.bat'
-          - 'vcvars64.bat'
-        options:
-          - 'pgo'
-
-        include:
-          - py: 'cpython-3.13'
-            vcvars: 'vcvars32.bat'
-            options: 'freethreaded+pgo'
-          - py: 'cpython-3.13'
-            vcvars: 'vcvars64.bat'
-            options: 'freethreaded+pgo'
-
-    needs: pythonbuild
-    runs-on: 'windows-2022'
-    steps:
-      - uses: actions/checkout@v4
-        with:
-          fetch-depth: 0
-
-      - name: Install Cygwin Environment
-        uses: cygwin/cygwin-install-action@49f298a7ebb00d4b3ddf58000c3e78eff5fbd6b9
-        with:
-          packages: autoconf automake libtool
-
-      - name: Install Python
-        uses: actions/setup-python@v5
-        with:
-          python-version: '3.11'
-
-      - name: Download pythonbuild Executable
-        uses: actions/download-artifact@v4
-        with:
-          name: pythonbuild
-
-      # We need to do this before we activate the VC++ environment or else binary packages
-      # don't get compiled properly.
-      - name: Bootstrap Python environment
-        run: |
-          py.exe -3.9 build-windows.py --help
-
-      - name: Build
-        shell: cmd
-        run: |
-          call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\${{ matrix.vcvars }}"
-          py.exe -3.9 build-windows.py --python ${{ matrix.py }} --sh c:\cygwin\bin\sh.exe --options ${{ matrix.options }}
-
-      - name: Validate Distribution
-        run: |
-          $Dists = Resolve-Path -Path "dist/*.tar.zst" -Relative
-          .\pythonbuild.exe validate-distribution --run $Dists
-
-      - name: Upload Distributions
-        uses: actions/upload-artifact@v4
-        with:
-          name: ${{ matrix.py }}-${{ matrix.vcvars }}-${{ matrix.options }}
-          path: dist/*
diff --git a/build-macos.py b/build-macos.py
index d2d8cd84..0061fc13 100755
--- a/build-macos.py
+++ b/build-macos.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.12
+#!/usr/bin/env python3
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at https://mozilla.org/MPL/2.0/.
diff --git a/cpython-unix/build-cpython.sh b/cpython-unix/build-cpython.sh
index 074ec0c1..ddc46a17 100755
--- a/cpython-unix/build-cpython.sh
+++ b/cpython-unix/build-cpython.sh
@@ -179,13 +179,20 @@ else
     patch -p1 -i ${ROOT}/patch-ctypes-callproc-legacy.patch
 fi
 
+# On Windows, CPython looks for the Tcl/Tk libraries relative to the base prefix,
+# with we want. But on Unix, it doesn't. This patch applies similar behavior on Unix,
+# thereby ensuring that the Tcl/Tk libraries are found in the correct location.
+# A similar patch could be applied to other CPython versions, but would require
+# customizations for each minor.
+if [ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_13}" ]; then
+    patch -p1 -i ${ROOT}/patch-tkinter-3.13.patch
+fi
+
 # Code that runs at ctypes module import time does not work with
 # non-dynamic binaries. Patch Python to work around this.
 # See https://bugs.python.org/issue37060.
 patch -p1 -i ${ROOT}/patch-ctypes-static-binary.patch
 
-patch -p1 -i ${ROOT}/patch-tkinter.patch
-
 # Older versions of Python need patching to work with modern mpdecimal.
 if [ -n "${PYTHON_MEETS_MAXIMUM_VERSION_3_9}" ]; then
     patch -p1 -i ${ROOT}/patch-decimal-modern-mpdecimal.patch
diff --git a/cpython-unix/build-main.py b/cpython-unix/build-main.py
index 24d0b485..1e310b22 100755
--- a/cpython-unix/build-main.py
+++ b/cpython-unix/build-main.py
@@ -69,7 +69,7 @@ def main():
             "cpython-3.12",
             "cpython-3.13",
         },
-        default="cpython-3.13",
+        default="cpython-3.11",
         help="Python distribution to build",
     )
     parser.add_argument(
diff --git a/cpython-unix/patch-tkinter.patch b/cpython-unix/patch-tkinter-3.13.patch
similarity index 82%
rename from cpython-unix/patch-tkinter.patch
rename to cpython-unix/patch-tkinter-3.13.patch
index dd818936..42d88241 100644
--- a/cpython-unix/patch-tkinter.patch
+++ b/cpython-unix/patch-tkinter-3.13.patch
@@ -1,8 +1,20 @@
 diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c
-index 45897817a56..c18808e10c7 100644
+index 45897817a56..671b3dfc3d0 100644
 --- a/Modules/_tkinter.c
 +++ b/Modules/_tkinter.c
-@@ -132,6 +132,7 @@ typedef int Tcl_Size;
+@@ -26,9 +26,8 @@ Copyright (C) 1994 Steen Lumholt.
+ #endif
+ 
+ #include "Python.h"
+-#ifdef MS_WINDOWS
+-#  include "pycore_fileutils.h"   // _Py_stat()
+-#endif
++
++#include "pycore_fileutils.h"     // _Py_stat()
+ 
+ #include "pycore_long.h"          // _PyLong_IsNegative()
+ 
+@@ -132,6 +131,7 @@ typedef int Tcl_Size;
  #ifdef MS_WINDOWS
  #include <conio.h>
  #define WAIT_FOR_STDIN
@@ -10,7 +22,7 @@ index 45897817a56..c18808e10c7 100644
  
  static PyObject *
  _get_tcl_lib_path(void)
-@@ -148,6 +149,7 @@ _get_tcl_lib_path(void)
+@@ -148,6 +148,7 @@ _get_tcl_lib_path(void)
              return NULL;
          }
  
@@ -18,12 +30,12 @@ index 45897817a56..c18808e10c7 100644
          /* Check expected location for an installed Python first */
          tcl_library_path = PyUnicode_FromString("\\tcl\\tcl" TCL_VERSION);
          if (tcl_library_path == NULL) {
-@@ -185,11 +187,31 @@ _get_tcl_lib_path(void)
+@@ -185,11 +186,31 @@ _get_tcl_lib_path(void)
              tcl_library_path = NULL;
  #endif
          }
 +#else
-+        /* Unix - check expected location for an installed Python */
++        /* Check expected location for an installed Python first */
 +        tcl_library_path = PyUnicode_FromString("/lib/tcl" TCL_VERSION);
 +        if (tcl_library_path == NULL) {
 +            return NULL;
@@ -51,7 +63,7 @@ index 45897817a56..c18808e10c7 100644
  
  /* The threading situation is complicated.  Tcl is not thread-safe, except
     when configured with --enable-threads.
-@@ -710,6 +732,30 @@ Tkapp_New(const char *screenName, const char *className,
+@@ -710,6 +731,30 @@ Tkapp_New(const char *screenName, const char *className,
  
          ret = GetEnvironmentVariableW(L"TCL_LIBRARY", NULL, 0);
          if (!ret && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
@@ -82,14 +94,6 @@ index 45897817a56..c18808e10c7 100644
              str_path = _get_tcl_lib_path();
              if (str_path == NULL && PyErr_Occurred()) {
                  return NULL;
-@@ -740,7 +786,6 @@ Tkapp_New(const char *screenName, const char *className,
-     return v;
- }
- 
--
- static void
- Tkapp_ThreadSend(TkappObject *self, Tcl_Event *ev,
-                  Tcl_Condition *cond, Tcl_Mutex *mutex)
 @@ -3552,7 +3597,27 @@ PyInit__tkinter(void)
                  PyMem_Free(wcs_path);
              }
@@ -118,3 +122,6 @@ index 45897817a56..c18808e10c7 100644
  #endif /* MS_WINDOWS */
          }
          Py_XDECREF(cexe);
+diff --git a/patch-tkinter.patch b/patch-tkinter.patch
+new file mode 100644
+index 00000000000..e69de29bb2d

From 14ab16fa48b2604dfeecfa04ba18350bf237d334 Mon Sep 17 00:00:00 2001
From: Charlie Marsh <charlie.r.marsh@gmail.com>
Date: Mon, 16 Dec 2024 12:53:35 -0500
Subject: [PATCH 4/5] Add patches for all versions

---
 build-macos.py                        |   2 +-
 cpython-unix/build-cpython.sh         |  14 ++-
 cpython-unix/patch-tkinter-3.10.patch | 112 +++++++++++++++++++++++
 cpython-unix/patch-tkinter-3.11.patch | 123 ++++++++++++++++++++++++++
 cpython-unix/patch-tkinter-3.12.patch | 123 ++++++++++++++++++++++++++
 cpython-unix/patch-tkinter-3.9.patch  | 112 +++++++++++++++++++++++
 6 files changed, 481 insertions(+), 5 deletions(-)
 create mode 100644 cpython-unix/patch-tkinter-3.10.patch
 create mode 100644 cpython-unix/patch-tkinter-3.11.patch
 create mode 100644 cpython-unix/patch-tkinter-3.12.patch
 create mode 100644 cpython-unix/patch-tkinter-3.9.patch

diff --git a/build-macos.py b/build-macos.py
index 0061fc13..d2d8cd84 100755
--- a/build-macos.py
+++ b/build-macos.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python3.12
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at https://mozilla.org/MPL/2.0/.
diff --git a/cpython-unix/build-cpython.sh b/cpython-unix/build-cpython.sh
index ddc46a17..c84081ba 100755
--- a/cpython-unix/build-cpython.sh
+++ b/cpython-unix/build-cpython.sh
@@ -180,12 +180,18 @@ else
 fi
 
 # On Windows, CPython looks for the Tcl/Tk libraries relative to the base prefix,
-# with we want. But on Unix, it doesn't. This patch applies similar behavior on Unix,
+# which we want. But on Unix, it doesn't. This patch applies similar behavior on Unix,
 # thereby ensuring that the Tcl/Tk libraries are found in the correct location.
-# A similar patch could be applied to other CPython versions, but would require
-# customizations for each minor.
-if [ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_13}" ]; then
+if [ "${PYTHON_MAJMIN_VERSION}" = "3.13" ]; then
     patch -p1 -i ${ROOT}/patch-tkinter-3.13.patch
+elif [ "${PYTHON_MAJMIN_VERSION}" = "3.12" ]; then
+    patch -p1 -i ${ROOT}/patch-tkinter-3.12.patch
+elif [ "${PYTHON_MAJMIN_VERSION}" = "3.11" ]; then
+    patch -p1 -i ${ROOT}/patch-tkinter-3.11.patch
+elif [ "${PYTHON_MAJMIN_VERSION}" = "3.10" ]; then
+    patch -p1 -i ${ROOT}/patch-tkinter-3.10.patch
+else
+    patch -p1 -i ${ROOT}/patch-tkinter-3.9.patch
 fi
 
 # Code that runs at ctypes module import time does not work with
diff --git a/cpython-unix/patch-tkinter-3.10.patch b/cpython-unix/patch-tkinter-3.10.patch
new file mode 100644
index 00000000..eb288659
--- /dev/null
+++ b/cpython-unix/patch-tkinter-3.10.patch
@@ -0,0 +1,112 @@
+diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c
+index 2a3e65b6c97..b17c5bfd6b1 100644
+--- a/Modules/_tkinter.c
++++ b/Modules/_tkinter.c
+@@ -115,6 +115,7 @@ Copyright (C) 1994 Steen Lumholt.
+ #ifdef MS_WINDOWS
+ #include <conio.h>
+ #define WAIT_FOR_STDIN
++#endif
+ 
+ static PyObject *
+ _get_tcl_lib_path()
+@@ -132,6 +133,7 @@ _get_tcl_lib_path()
+             return NULL;
+         }
+ 
++#ifdef MS_WINDOWS
+         /* Check expected location for an installed Python first */
+         tcl_library_path = PyUnicode_FromString("\\tcl\\tcl" TCL_VERSION);
+         if (tcl_library_path == NULL) {
+@@ -169,11 +171,31 @@ _get_tcl_lib_path()
+             tcl_library_path = NULL;
+ #endif
+         }
++#else
++        /* Check expected location for an installed Python first */
++        tcl_library_path = PyUnicode_FromString("/lib/tcl" TCL_VERSION);
++        if (tcl_library_path == NULL) {
++            return NULL;
++        }
++        tcl_library_path = PyUnicode_Concat(prefix, tcl_library_path);
++        if (tcl_library_path == NULL) {
++            return NULL;
++        }
++        stat_return_value = _Py_stat(tcl_library_path, &stat_buf);
++        if (stat_return_value == -2) {
++            return NULL;
++        }
++        if (stat_return_value == -1) {
++            /* install location doesn't exist, reset errno and leave Tcl
++               to its own devices */
++            errno = 0;
++            tcl_library_path = NULL;
++        }
++#endif
+         already_checked = 1;
+     }
+     return tcl_library_path;
+ }
+-#endif /* MS_WINDOWS */
+ 
+ /* The threading situation is complicated.  Tcl is not thread-safe, except
+    when configured with --enable-threads.
+@@ -822,6 +844,30 @@ Tkapp_New(const char *screenName, const char *className,
+ 
+         ret = GetEnvironmentVariableW(L"TCL_LIBRARY", NULL, 0);
+         if (!ret && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
++            str_path = _get_tcl_lib_path();
++            if (str_path == NULL && PyErr_Occurred()) {
++                return NULL;
++            }
++            if (str_path != NULL) {
++                utf8_path = PyUnicode_AsUTF8String(str_path);
++                if (utf8_path == NULL) {
++                    return NULL;
++                }
++                Tcl_SetVar(v->interp,
++                           "tcl_library",
++                           PyBytes_AS_STRING(utf8_path),
++                           TCL_GLOBAL_ONLY);
++                Py_DECREF(utf8_path);
++            }
++        }
++    }
++#else
++    {
++        const char *env_val = getenv("TCL_LIBRARY");
++        if (!env_val) {
++            PyObject *str_path;
++            PyObject *utf8_path;
++
+             str_path = _get_tcl_lib_path();
+             if (str_path == NULL && PyErr_Occurred()) {
+                 return NULL;
+@@ -3628,7 +3674,27 @@ PyInit__tkinter(void)
+                 PyMem_Free(wcs_path);
+             }
+ #else
++            int set_var = 0;
++            PyObject *str_path;
++            char *path;
++
++            if (!getenv("TCL_LIBRARY")) {
++                str_path = _get_tcl_lib_path();
++                if (str_path == NULL && PyErr_Occurred()) {
++                    Py_DECREF(m);
++                    return NULL;
++                }
++                if (str_path != NULL) {
++                    setenv("TCL_LIBRARY", path, 1);
++                    set_var = 1;
++                }
++            }
++
+             Tcl_FindExecutable(PyBytes_AS_STRING(cexe));
++
++            if (set_var) {
++                unsetenv("TCL_LIBRARY");
++            }
+ #endif /* MS_WINDOWS */
+         }
+         Py_XDECREF(cexe);
diff --git a/cpython-unix/patch-tkinter-3.11.patch b/cpython-unix/patch-tkinter-3.11.patch
new file mode 100644
index 00000000..9465d607
--- /dev/null
+++ b/cpython-unix/patch-tkinter-3.11.patch
@@ -0,0 +1,123 @@
+diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c
+index 005036d3ff2..c130ed7b186 100644
+--- a/Modules/_tkinter.c
++++ b/Modules/_tkinter.c
+@@ -28,9 +28,7 @@ Copyright (C) 1994 Steen Lumholt.
+ 
+ #include "Python.h"
+ #include <ctype.h>
+-#ifdef MS_WINDOWS
+-#  include "pycore_fileutils.h"   // _Py_stat()
+-#endif
++#include "pycore_fileutils.h"   // _Py_stat()
+ 
+ #ifdef MS_WINDOWS
+ #include <windows.h>
+@@ -123,6 +121,7 @@ Copyright (C) 1994 Steen Lumholt.
+ #ifdef MS_WINDOWS
+ #include <conio.h>
+ #define WAIT_FOR_STDIN
++#endif
+ 
+ static PyObject *
+ _get_tcl_lib_path()
+@@ -140,6 +139,7 @@ _get_tcl_lib_path()
+             return NULL;
+         }
+ 
++#ifdef MS_WINDOWS
+         /* Check expected location for an installed Python first */
+         tcl_library_path = PyUnicode_FromString("\\tcl\\tcl" TCL_VERSION);
+         if (tcl_library_path == NULL) {
+@@ -177,11 +177,31 @@ _get_tcl_lib_path()
+             tcl_library_path = NULL;
+ #endif
+         }
++#else
++        /* Check expected location for an installed Python first */
++        tcl_library_path = PyUnicode_FromString("/lib/tcl" TCL_VERSION);
++        if (tcl_library_path == NULL) {
++            return NULL;
++        }
++        tcl_library_path = PyUnicode_Concat(prefix, tcl_library_path);
++        if (tcl_library_path == NULL) {
++            return NULL;
++        }
++        stat_return_value = _Py_stat(tcl_library_path, &stat_buf);
++        if (stat_return_value == -2) {
++            return NULL;
++        }
++        if (stat_return_value == -1) {
++            /* install location doesn't exist, reset errno and leave Tcl
++               to its own devices */
++            errno = 0;
++            tcl_library_path = NULL;
++        }
++#endif
+         already_checked = 1;
+     }
+     return tcl_library_path;
+ }
+-#endif /* MS_WINDOWS */
+ 
+ /* The threading situation is complicated.  Tcl is not thread-safe, except
+    when configured with --enable-threads.
+@@ -687,6 +707,30 @@ Tkapp_New(const char *screenName, const char *className,
+ 
+         ret = GetEnvironmentVariableW(L"TCL_LIBRARY", NULL, 0);
+         if (!ret && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
++            str_path = _get_tcl_lib_path();
++            if (str_path == NULL && PyErr_Occurred()) {
++                return NULL;
++            }
++            if (str_path != NULL) {
++                utf8_path = PyUnicode_AsUTF8String(str_path);
++                if (utf8_path == NULL) {
++                    return NULL;
++                }
++                Tcl_SetVar(v->interp,
++                           "tcl_library",
++                           PyBytes_AS_STRING(utf8_path),
++                           TCL_GLOBAL_ONLY);
++                Py_DECREF(utf8_path);
++            }
++        }
++    }
++#else
++    {
++        const char *env_val = getenv("TCL_LIBRARY");
++        if (!env_val) {
++            PyObject *str_path;
++            PyObject *utf8_path;
++
+             str_path = _get_tcl_lib_path();
+             if (str_path == NULL && PyErr_Occurred()) {
+                 return NULL;
+@@ -3428,7 +3472,27 @@ PyInit__tkinter(void)
+                 PyMem_Free(wcs_path);
+             }
+ #else
++            int set_var = 0;
++            PyObject *str_path;
++            char *path;
++
++            if (!getenv("TCL_LIBRARY")) {
++                str_path = _get_tcl_lib_path();
++                if (str_path == NULL && PyErr_Occurred()) {
++                    Py_DECREF(m);
++                    return NULL;
++                }
++                if (str_path != NULL) {
++                    setenv("TCL_LIBRARY", path, 1);
++                    set_var = 1;
++                }
++            }
++
+             Tcl_FindExecutable(PyBytes_AS_STRING(cexe));
++
++            if (set_var) {
++                unsetenv("TCL_LIBRARY");
++            }
+ #endif /* MS_WINDOWS */
+         }
+         Py_XDECREF(cexe);
diff --git a/cpython-unix/patch-tkinter-3.12.patch b/cpython-unix/patch-tkinter-3.12.patch
new file mode 100644
index 00000000..bff6b0ed
--- /dev/null
+++ b/cpython-unix/patch-tkinter-3.12.patch
@@ -0,0 +1,123 @@
+diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c
+index 6b5fcb8a365..99d44ccf1d8 100644
+--- a/Modules/_tkinter.c
++++ b/Modules/_tkinter.c
+@@ -28,9 +28,7 @@ Copyright (C) 1994 Steen Lumholt.
+ 
+ #include "Python.h"
+ #include <ctype.h>
+-#ifdef MS_WINDOWS
+-#  include "pycore_fileutils.h"   // _Py_stat()
+-#endif
++#include "pycore_fileutils.h"   // _Py_stat()
+ 
+ #include "pycore_long.h"
+ 
+@@ -134,6 +132,7 @@ typedef int Tcl_Size;
+ #ifdef MS_WINDOWS
+ #include <conio.h>
+ #define WAIT_FOR_STDIN
++#endif
+ 
+ static PyObject *
+ _get_tcl_lib_path(void)
+@@ -151,6 +150,7 @@ _get_tcl_lib_path(void)
+             return NULL;
+         }
+ 
++#ifdef MS_WINDOWS
+         /* Check expected location for an installed Python first */
+         tcl_library_path = PyUnicode_FromString("\\tcl\\tcl" TCL_VERSION);
+         if (tcl_library_path == NULL) {
+@@ -188,11 +188,31 @@ _get_tcl_lib_path(void)
+             tcl_library_path = NULL;
+ #endif
+         }
++#else
++        /* Check expected location for an installed Python first */
++        tcl_library_path = PyUnicode_FromString("/lib/tcl" TCL_VERSION);
++        if (tcl_library_path == NULL) {
++            return NULL;
++        }
++        tcl_library_path = PyUnicode_Concat(prefix, tcl_library_path);
++        if (tcl_library_path == NULL) {
++            return NULL;
++        }
++        stat_return_value = _Py_stat(tcl_library_path, &stat_buf);
++        if (stat_return_value == -2) {
++            return NULL;
++        }
++        if (stat_return_value == -1) {
++            /* install location doesn't exist, reset errno and leave Tcl
++               to its own devices */
++            errno = 0;
++            tcl_library_path = NULL;
++        }
++#endif
+         already_checked = 1;
+     }
+     return tcl_library_path;
+ }
+-#endif /* MS_WINDOWS */
+ 
+ /* The threading situation is complicated.  Tcl is not thread-safe, except
+    when configured with --enable-threads.
+@@ -713,6 +733,30 @@ Tkapp_New(const char *screenName, const char *className,
+ 
+         ret = GetEnvironmentVariableW(L"TCL_LIBRARY", NULL, 0);
+         if (!ret && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
++            str_path = _get_tcl_lib_path();
++            if (str_path == NULL && PyErr_Occurred()) {
++                return NULL;
++            }
++            if (str_path != NULL) {
++                utf8_path = PyUnicode_AsUTF8String(str_path);
++                if (utf8_path == NULL) {
++                    return NULL;
++                }
++                Tcl_SetVar(v->interp,
++                           "tcl_library",
++                           PyBytes_AS_STRING(utf8_path),
++                           TCL_GLOBAL_ONLY);
++                Py_DECREF(utf8_path);
++            }
++        }
++    }
++#else
++    {
++        const char *env_val = getenv("TCL_LIBRARY");
++        if (!env_val) {
++            PyObject *str_path;
++            PyObject *utf8_path;
++
+             str_path = _get_tcl_lib_path();
+             if (str_path == NULL && PyErr_Occurred()) {
+                 return NULL;
+@@ -3542,7 +3586,27 @@ PyInit__tkinter(void)
+                 PyMem_Free(wcs_path);
+             }
+ #else
++            int set_var = 0;
++            PyObject *str_path;
++            char *path;
++
++            if (!getenv("TCL_LIBRARY")) {
++                str_path = _get_tcl_lib_path();
++                if (str_path == NULL && PyErr_Occurred()) {
++                    Py_DECREF(m);
++                    return NULL;
++                }
++                if (str_path != NULL) {
++                    setenv("TCL_LIBRARY", path, 1);
++                    set_var = 1;
++                }
++            }
++
+             Tcl_FindExecutable(PyBytes_AS_STRING(cexe));
++
++            if (set_var) {
++                unsetenv("TCL_LIBRARY");
++            }
+ #endif /* MS_WINDOWS */
+         }
+         Py_XDECREF(cexe);
diff --git a/cpython-unix/patch-tkinter-3.9.patch b/cpython-unix/patch-tkinter-3.9.patch
new file mode 100644
index 00000000..1d063b2b
--- /dev/null
+++ b/cpython-unix/patch-tkinter-3.9.patch
@@ -0,0 +1,112 @@
+diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c
+index e153047b778..5dbaf2e3e6e 100644
+--- a/Modules/_tkinter.c
++++ b/Modules/_tkinter.c
+@@ -115,6 +115,7 @@ Copyright (C) 1994 Steen Lumholt.
+ #ifdef MS_WINDOWS
+ #include <conio.h>
+ #define WAIT_FOR_STDIN
++#endif
+ 
+ static PyObject *
+ _get_tcl_lib_path()
+@@ -132,6 +133,7 @@ _get_tcl_lib_path()
+             return NULL;
+         }
+ 
++#ifdef MS_WINDOWS
+         /* Check expected location for an installed Python first */
+         tcl_library_path = PyUnicode_FromString("\\tcl\\tcl" TCL_VERSION);
+         if (tcl_library_path == NULL) {
+@@ -169,11 +171,31 @@ _get_tcl_lib_path()
+             tcl_library_path = NULL;
+ #endif
+         }
++#else
++        /* Check expected location for an installed Python first */
++        tcl_library_path = PyUnicode_FromString("/lib/tcl" TCL_VERSION);
++        if (tcl_library_path == NULL) {
++            return NULL;
++        }
++        tcl_library_path = PyUnicode_Concat(prefix, tcl_library_path);
++        if (tcl_library_path == NULL) {
++            return NULL;
++        }
++        stat_return_value = _Py_stat(tcl_library_path, &stat_buf);
++        if (stat_return_value == -2) {
++            return NULL;
++        }
++        if (stat_return_value == -1) {
++            /* install location doesn't exist, reset errno and leave Tcl
++               to its own devices */
++            errno = 0;
++            tcl_library_path = NULL;
++        }
++#endif
+         already_checked = 1;
+     }
+     return tcl_library_path;
+ }
+-#endif /* MS_WINDOWS */
+ 
+ /* The threading situation is complicated.  Tcl is not thread-safe, except
+    when configured with --enable-threads.
+@@ -822,6 +844,30 @@ Tkapp_New(const char *screenName, const char *className,
+ 
+         ret = GetEnvironmentVariableW(L"TCL_LIBRARY", NULL, 0);
+         if (!ret && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
++            str_path = _get_tcl_lib_path();
++            if (str_path == NULL && PyErr_Occurred()) {
++                return NULL;
++            }
++            if (str_path != NULL) {
++                utf8_path = PyUnicode_AsUTF8String(str_path);
++                if (utf8_path == NULL) {
++                    return NULL;
++                }
++                Tcl_SetVar(v->interp,
++                           "tcl_library",
++                           PyBytes_AS_STRING(utf8_path),
++                           TCL_GLOBAL_ONLY);
++                Py_DECREF(utf8_path);
++            }
++        }
++    }
++#else
++    {
++        const char *env_val = getenv("TCL_LIBRARY");
++        if (!env_val) {
++            PyObject *str_path;
++            PyObject *utf8_path;
++
+             str_path = _get_tcl_lib_path();
+             if (str_path == NULL && PyErr_Occurred()) {
+                 return NULL;
+@@ -3631,7 +3677,27 @@ PyInit__tkinter(void)
+                 PyMem_Free(wcs_path);
+             }
+ #else
++            int set_var = 0;
++            PyObject *str_path;
++            char *path;
++
++            if (!getenv("TCL_LIBRARY")) {
++                str_path = _get_tcl_lib_path();
++                if (str_path == NULL && PyErr_Occurred()) {
++                    Py_DECREF(m);
++                    return NULL;
++                }
++                if (str_path != NULL) {
++                    setenv("TCL_LIBRARY", path, 1);
++                    set_var = 1;
++                }
++            }
++
+             Tcl_FindExecutable(PyBytes_AS_STRING(cexe));
++
++            if (set_var) {
++                unsetenv("TCL_LIBRARY");
++            }
+ #endif /* MS_WINDOWS */
+         }
+         Py_XDECREF(cexe);

From cc78c11cc58f114d90575d5ce08d7b7e375a6ef7 Mon Sep 17 00:00:00 2001
From: Charlie Marsh <charlie.r.marsh@gmail.com>
Date: Mon, 16 Dec 2024 13:12:59 -0500
Subject: [PATCH 5/5] CI reverts

---
 .github/workflows/apple.yml   | 253 ++++++++++
 .github/workflows/linux.yml   | 865 ++++++++++++++++++++++++++++++++++
 .github/workflows/windows.yml | 110 +++++
 build-macos.py                |   2 +-
 4 files changed, 1229 insertions(+), 1 deletion(-)
 create mode 100644 .github/workflows/apple.yml
 create mode 100644 .github/workflows/windows.yml

diff --git a/.github/workflows/apple.yml b/.github/workflows/apple.yml
new file mode 100644
index 00000000..f20bc3c4
--- /dev/null
+++ b/.github/workflows/apple.yml
@@ -0,0 +1,253 @@
+name: MacOS Python build
+
+on:
+  push:
+    branches: [main]
+  pull_request:
+
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.sha }}
+  cancel-in-progress: ${{ github.event_name == 'pull_request' }}
+
+env:
+  FORCE_COLOR: 1
+
+jobs:
+  pythonbuild:
+    runs-on: 'macos-13'
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Emit rustc version
+        run: |
+          rustc --version > .rustc-version
+
+      - uses: actions/cache@v4
+        with:
+          path: |
+            ~/.cargo/registry
+            ~/.cargo/git
+            target
+          key: ${{ runner.os }}-pythonbuild-${{ hashFiles('Cargo.lock', '.rustc-version') }}
+
+      - name: Build
+        run: |
+          cargo build --release
+
+      - name: Upload pythonbuild Executable
+        uses: actions/upload-artifact@v4
+        with:
+          name: pythonbuild
+          path: target/release/pythonbuild
+
+  build:
+    strategy:
+      fail-fast: false
+      matrix:
+        build:
+          - target_triple: 'aarch64-apple-darwin'
+            runner: macos-14
+            py: 'cpython-3.9'
+            options: 'debug'
+          - target_triple: 'aarch64-apple-darwin'
+            runner: macos-14
+            py: 'cpython-3.9'
+            options: 'pgo'
+          - target_triple: 'aarch64-apple-darwin'
+            runner: macos-14
+            py: 'cpython-3.9'
+            options: 'pgo+lto'
+
+          - target_triple: 'aarch64-apple-darwin'
+            runner: macos-14
+            py: 'cpython-3.10'
+            options: 'debug'
+          - target_triple: 'aarch64-apple-darwin'
+            runner: macos-14
+            py: 'cpython-3.10'
+            options: 'pgo'
+          - target_triple: 'aarch64-apple-darwin'
+            runner: macos-14
+            py: 'cpython-3.10'
+            options: 'pgo+lto'
+
+          - target_triple: 'aarch64-apple-darwin'
+            runner: macos-14
+            py: 'cpython-3.11'
+            options: 'debug'
+          - target_triple: 'aarch64-apple-darwin'
+            runner: macos-14
+            py: 'cpython-3.11'
+            options: 'pgo'
+          - target_triple: 'aarch64-apple-darwin'
+            runner: macos-14
+            py: 'cpython-3.11'
+            options: 'pgo+lto'
+
+          - target_triple: 'aarch64-apple-darwin'
+            runner: macos-14
+            py: 'cpython-3.12'
+            options: 'debug'
+          - target_triple: 'aarch64-apple-darwin'
+            runner: macos-14
+            py: 'cpython-3.12'
+            options: 'pgo'
+          - target_triple: 'aarch64-apple-darwin'
+            runner: macos-14
+            py: 'cpython-3.12'
+            options: 'pgo+lto'
+
+          - target_triple: 'aarch64-apple-darwin'
+            runner: macos-14
+            py: 'cpython-3.13'
+            options: 'debug'
+          - target_triple: 'aarch64-apple-darwin'
+            runner: macos-14
+            py: 'cpython-3.13'
+            options: 'pgo'
+          - target_triple: 'aarch64-apple-darwin'
+            runner: macos-14
+            py: 'cpython-3.13'
+            options: 'pgo+lto'
+
+          - target_triple: 'aarch64-apple-darwin'
+            runner: macos-14
+            py: 'cpython-3.13'
+            options: 'freethreaded+debug'
+          - target_triple: 'aarch64-apple-darwin'
+            runner: macos-14
+            py: 'cpython-3.13'
+            options: 'freethreaded+pgo'
+          - target_triple: 'aarch64-apple-darwin'
+            runner: macos-14
+            py: 'cpython-3.13'
+            options: 'freethreaded+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.
+          - target_triple: 'x86_64-apple-darwin'
+            runner: macos-13
+            py: 'cpython-3.9'
+            options: 'debug'
+          - target_triple: 'x86_64-apple-darwin'
+            runner: macos-13
+            py: 'cpython-3.9'
+            options: 'pgo'
+          - target_triple: 'x86_64-apple-darwin'
+            runner: macos-13
+            py: 'cpython-3.9'
+            options: 'pgo+lto'
+
+          - target_triple: 'x86_64-apple-darwin'
+            runner: macos-13
+            py: 'cpython-3.10'
+            options: 'debug'
+          - target_triple: 'x86_64-apple-darwin'
+            runner: macos-13
+            py: 'cpython-3.10'
+            options: 'pgo'
+          - target_triple: 'x86_64-apple-darwin'
+            runner: macos-13
+            py: 'cpython-3.10'
+            options: 'pgo+lto'
+
+          - target_triple: 'x86_64-apple-darwin'
+            runner: macos-13
+            py: 'cpython-3.11'
+            options: 'debug'
+          - target_triple: 'x86_64-apple-darwin'
+            runner: macos-13
+            py: 'cpython-3.11'
+            options: 'pgo'
+          - target_triple: 'x86_64-apple-darwin'
+            runner: macos-13
+            py: 'cpython-3.11'
+            options: 'pgo+lto'
+
+          - target_triple: 'x86_64-apple-darwin'
+            runner: macos-13
+            py: 'cpython-3.12'
+            options: 'debug'
+          - target_triple: 'x86_64-apple-darwin'
+            runner: macos-13
+            py: 'cpython-3.12'
+            options: 'pgo'
+          - target_triple: 'x86_64-apple-darwin'
+            runner: macos-13
+            py: 'cpython-3.12'
+            options: 'pgo+lto'
+
+          - target_triple: 'x86_64-apple-darwin'
+            runner: macos-13
+            py: 'cpython-3.13'
+            options: 'debug'
+          - target_triple: 'x86_64-apple-darwin'
+            runner: macos-13
+            py: 'cpython-3.13'
+            options: 'pgo'
+          - target_triple: 'x86_64-apple-darwin'
+            runner: macos-13
+            py: 'cpython-3.13'
+            options: 'pgo+lto'
+          - target_triple: 'x86_64-apple-darwin'
+            runner: macos-13
+            py: 'cpython-3.13'
+            options: 'freethreaded+debug'
+          - target_triple: 'x86_64-apple-darwin'
+            runner: macos-13
+            py: 'cpython-3.13'
+            options: 'freethreaded+pgo'
+          - target_triple: 'x86_64-apple-darwin'
+            runner: macos-13
+            py: 'cpython-3.13'
+            options: 'freethreaded+pgo+lto'
+    needs:
+      - pythonbuild
+    runs-on: ${{ matrix.build.runner }}
+    steps:
+      - uses: actions/checkout@v4
+        with:
+          fetch-depth: 0
+
+      - name: Install Python
+        uses: actions/setup-python@v5
+        with:
+          python-version: '3.11'
+
+      - name: Download pythonbuild
+        uses: actions/download-artifact@v4
+        with:
+          name: pythonbuild
+          path: build
+
+      - name: Build
+        run: |
+          if [ "${{ matrix.build.target_triple }}" = "aarch64-apple-darwin" ]; then
+            export APPLE_SDK_PATH=/Applications/Xcode_15.2.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.2.sdk
+          elif [ "${{ matrix.build.target_triple }}" = "x86_64-apple-darwin" ]; then
+            export APPLE_SDK_PATH=/Applications/Xcode_15.2.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.2.sdk
+          else
+            echo "unhandled target triple: ${{ matrix.build.target_triple }}"
+            exit 1
+          fi
+
+          ./build-macos.py --target-triple ${{ matrix.build.target_triple }} --python ${{ matrix.build.py }} --options ${{ matrix.build.options }}
+
+      - name: Upload Distributions
+        uses: actions/upload-artifact@v4
+        with:
+          name: ${{ matrix.build.py }}-${{ matrix.build.target_triple }}-${{ matrix.build.options }}
+          path: dist/*
+
+      - uses: actions/checkout@v4
+        with:
+          repository: 'phracker/MacOSX-SDKs'
+          ref: master
+          path: macosx-sdks
+
+      - name: Validate Distribution
+        run: |
+          chmod +x build/pythonbuild
+
+          build/pythonbuild validate-distribution --macos-sdks-path macosx-sdks --run dist/*.tar.zst
diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml
index 5228640b..8e006509 100644
--- a/.github/workflows/linux.yml
+++ b/.github/workflows/linux.yml
@@ -120,25 +120,607 @@ jobs:
       fail-fast: false
       matrix:
         build:
+          # Cross-compiles can't do PGO.
+
+          - target_triple: 'aarch64-unknown-linux-gnu'
+            py: 'cpython-3.9'
+            options: 'debug'
+          - target_triple: 'aarch64-unknown-linux-gnu'
+            py: 'cpython-3.9'
+            options: 'noopt'
+          - target_triple: 'aarch64-unknown-linux-gnu'
+            py: 'cpython-3.9'
+            options: 'lto'
+
+          - target_triple: 'aarch64-unknown-linux-gnu'
+            py: 'cpython-3.10'
+            options: 'debug'
+          - target_triple: 'aarch64-unknown-linux-gnu'
+            py: 'cpython-3.10'
+            options: 'noopt'
+          - target_triple: 'aarch64-unknown-linux-gnu'
+            py: 'cpython-3.10'
+            options: 'lto'
+
+          - target_triple: 'aarch64-unknown-linux-gnu'
+            py: 'cpython-3.11'
+            options: 'debug'
+          - target_triple: 'aarch64-unknown-linux-gnu'
+            py: 'cpython-3.11'
+            options: 'noopt'
+          - target_triple: 'aarch64-unknown-linux-gnu'
+            py: 'cpython-3.11'
+            options: 'lto'
+
+          - target_triple: 'aarch64-unknown-linux-gnu'
+            py: 'cpython-3.12'
+            options: 'debug'
+          - target_triple: 'aarch64-unknown-linux-gnu'
+            py: 'cpython-3.12'
+            options: 'noopt'
+          - target_triple: 'aarch64-unknown-linux-gnu'
+            py: 'cpython-3.12'
+            options: 'lto'
+
+          # Cross-compiles can't do PGO and require Python 3.9.
+          - target_triple: 'armv7-unknown-linux-gnueabi'
+            py: 'cpython-3.9'
+            options: 'debug'
+          - target_triple: 'armv7-unknown-linux-gnueabi'
+            py: 'cpython-3.9'
+            options: 'noopt'
+          - target_triple: 'armv7-unknown-linux-gnueabi'
+            py: 'cpython-3.9'
+            options: 'lto'
+
+          - target_triple: 'armv7-unknown-linux-gnueabi'
+            py: 'cpython-3.10'
+            options: 'debug'
+          - target_triple: 'armv7-unknown-linux-gnueabi'
+            py: 'cpython-3.10'
+            options: 'noopt'
+          - target_triple: 'armv7-unknown-linux-gnueabi'
+            py: 'cpython-3.10'
+            options: 'lto'
+
+          - target_triple: 'armv7-unknown-linux-gnueabi'
+            py: 'cpython-3.11'
+            options: 'debug'
+          - target_triple: 'armv7-unknown-linux-gnueabi'
+            py: 'cpython-3.11'
+            options: 'noopt'
+          - target_triple: 'armv7-unknown-linux-gnueabi'
+            py: 'cpython-3.11'
+            options: 'lto'
+
+          - target_triple: 'armv7-unknown-linux-gnueabi'
+            py: 'cpython-3.12'
+            options: 'debug'
+          - target_triple: 'armv7-unknown-linux-gnueabi'
+            py: 'cpython-3.12'
+            options: 'noopt'
+          - target_triple: 'armv7-unknown-linux-gnueabi'
+            py: 'cpython-3.12'
+            options: 'lto'
+
+          # Cross-compiles can't do PGO and require Python 3.9.
+          - target_triple: 'armv7-unknown-linux-gnueabihf'
+            py: 'cpython-3.9'
+            options: 'debug'
+          - target_triple: 'armv7-unknown-linux-gnueabihf'
+            py: 'cpython-3.9'
+            options: 'noopt'
+          - target_triple: 'armv7-unknown-linux-gnueabihf'
+            py: 'cpython-3.9'
+            options: 'lto'
+
+          - target_triple: 'armv7-unknown-linux-gnueabihf'
+            py: 'cpython-3.10'
+            options: 'debug'
+          - target_triple: 'armv7-unknown-linux-gnueabihf'
+            py: 'cpython-3.10'
+            options: 'noopt'
+          - target_triple: 'armv7-unknown-linux-gnueabihf'
+            py: 'cpython-3.10'
+            options: 'lto'
+
+          - target_triple: 'armv7-unknown-linux-gnueabihf'
+            py: 'cpython-3.11'
+            options: 'debug'
+          - target_triple: 'armv7-unknown-linux-gnueabihf'
+            py: 'cpython-3.11'
+            options: 'noopt'
+          - target_triple: 'armv7-unknown-linux-gnueabihf'
+            py: 'cpython-3.11'
+            options: 'lto'
+
+          - target_triple: 'armv7-unknown-linux-gnueabihf'
+            py: 'cpython-3.12'
+            options: 'debug'
+          - target_triple: 'armv7-unknown-linux-gnueabihf'
+            py: 'cpython-3.12'
+            options: 'noopt'
+          - target_triple: 'armv7-unknown-linux-gnueabihf'
+            py: 'cpython-3.12'
+            options: 'lto'
+
+          # Cross-compiles can't do PGO and require Python 3.9.
+          - target_triple: 's390x-unknown-linux-gnu'
+            py: 'cpython-3.9'
+            options: 'debug'
+          - target_triple: 's390x-unknown-linux-gnu'
+            py: 'cpython-3.9'
+            options: 'noopt'
+          - target_triple: 's390x-unknown-linux-gnu'
+            py: 'cpython-3.9'
+            options: 'lto'
+
+          - target_triple: 's390x-unknown-linux-gnu'
+            py: 'cpython-3.10'
+            options: 'debug'
+          - target_triple: 's390x-unknown-linux-gnu'
+            py: 'cpython-3.10'
+            options: 'noopt'
+          - target_triple: 's390x-unknown-linux-gnu'
+            py: 'cpython-3.10'
+            options: 'lto'
+
+          - target_triple: 's390x-unknown-linux-gnu'
+            py: 'cpython-3.11'
+            options: 'debug'
+          - target_triple: 's390x-unknown-linux-gnu'
+            py: 'cpython-3.11'
+            options: 'noopt'
+          - target_triple: 's390x-unknown-linux-gnu'
+            py: 'cpython-3.11'
+            options: 'lto'
+
+          - target_triple: 's390x-unknown-linux-gnu'
+            py: 'cpython-3.12'
+            options: 'debug'
+          - target_triple: 's390x-unknown-linux-gnu'
+            py: 'cpython-3.12'
+            options: 'noopt'
+          - target_triple: 's390x-unknown-linux-gnu'
+            py: 'cpython-3.12'
+            options: 'lto'
+
+          # Cross-compiles can't do PGO and require Python 3.9.
+          - target_triple: 'ppc64le-unknown-linux-gnu'
+            py: 'cpython-3.9'
+            options: 'debug'
+          - target_triple: 'ppc64le-unknown-linux-gnu'
+            py: 'cpython-3.9'
+            options: 'noopt'
+          - target_triple: 'ppc64le-unknown-linux-gnu'
+            py: 'cpython-3.9'
+            options: 'lto'
+
+          - target_triple: 'ppc64le-unknown-linux-gnu'
+            py: 'cpython-3.10'
+            options: 'debug'
+          - target_triple: 'ppc64le-unknown-linux-gnu'
+            py: 'cpython-3.10'
+            options: 'noopt'
+          - target_triple: 'ppc64le-unknown-linux-gnu'
+            py: 'cpython-3.10'
+            options: 'lto'
+
+          - target_triple: 'ppc64le-unknown-linux-gnu'
+            py: 'cpython-3.11'
+            options: 'debug'
+          - target_triple: 'ppc64le-unknown-linux-gnu'
+            py: 'cpython-3.11'
+            options: 'noopt'
+          - target_triple: 'ppc64le-unknown-linux-gnu'
+            py: 'cpython-3.11'
+            options: 'lto'
+
+          - target_triple: 'ppc64le-unknown-linux-gnu'
+            py: 'cpython-3.12'
+            options: 'debug'
+          - target_triple: 'ppc64le-unknown-linux-gnu'
+            py: 'cpython-3.12'
+            options: 'noopt'
+          - target_triple: 'ppc64le-unknown-linux-gnu'
+            py: 'cpython-3.12'
+            options: 'lto'
+
           - target_triple: 'x86_64-unknown-linux-gnu'
             py: 'cpython-3.9'
             options: 'debug'
             run: true
+          - target_triple: 'x86_64-unknown-linux-gnu'
+            py: 'cpython-3.9'
+            options: 'pgo'
+            run: true
+          - target_triple: 'x86_64-unknown-linux-gnu'
+            py: 'cpython-3.9'
+            options: 'pgo+lto'
+            run: true
 
           - target_triple: 'x86_64-unknown-linux-gnu'
             py: 'cpython-3.10'
             options: 'debug'
             run: true
+          - target_triple: 'x86_64-unknown-linux-gnu'
+            py: 'cpython-3.10'
+            options: 'pgo'
+            run: true
+          - target_triple: 'x86_64-unknown-linux-gnu'
+            py: 'cpython-3.10'
+            options: 'pgo+lto'
+            run: true
 
           - target_triple: 'x86_64-unknown-linux-gnu'
             py: 'cpython-3.11'
             options: 'debug'
             run: true
+          - target_triple: 'x86_64-unknown-linux-gnu'
+            py: 'cpython-3.11'
+            options: 'pgo'
+            run: true
+          - target_triple: 'x86_64-unknown-linux-gnu'
+            py: 'cpython-3.11'
+            options: 'pgo+lto'
+            run: true
 
           - target_triple: 'x86_64-unknown-linux-gnu'
             py: 'cpython-3.12'
             options: 'debug'
             run: true
+          - target_triple: 'x86_64-unknown-linux-gnu'
+            py: 'cpython-3.12'
+            options: 'pgo'
+            run: true
+          - target_triple: 'x86_64-unknown-linux-gnu'
+            py: 'cpython-3.12'
+            options: 'pgo+lto'
+            run: true
+
+          - target_triple: 'x86_64_v2-unknown-linux-gnu'
+            py: 'cpython-3.9'
+            options: 'debug'
+            run: true
+          - target_triple: 'x86_64_v2-unknown-linux-gnu'
+            py: 'cpython-3.9'
+            options: 'pgo'
+            run: true
+          - target_triple: 'x86_64_v2-unknown-linux-gnu'
+            py: 'cpython-3.9'
+            options: 'pgo+lto'
+            run: true
+
+          - target_triple: 'x86_64_v2-unknown-linux-gnu'
+            py: 'cpython-3.10'
+            options: 'debug'
+            run: true
+          - target_triple: 'x86_64_v2-unknown-linux-gnu'
+            py: 'cpython-3.10'
+            options: 'pgo'
+            run: true
+          - target_triple: 'x86_64_v2-unknown-linux-gnu'
+            py: 'cpython-3.10'
+            options: 'pgo+lto'
+            run: true
+
+          - target_triple: 'x86_64_v2-unknown-linux-gnu'
+            py: 'cpython-3.11'
+            options: 'debug'
+            run: true
+          - target_triple: 'x86_64_v2-unknown-linux-gnu'
+            py: 'cpython-3.11'
+            options: 'pgo'
+            run: true
+          - target_triple: 'x86_64_v2-unknown-linux-gnu'
+            py: 'cpython-3.11'
+            options: 'pgo+lto'
+            run: true
+
+          - target_triple: 'x86_64_v2-unknown-linux-gnu'
+            py: 'cpython-3.12'
+            options: 'debug'
+            run: true
+          - target_triple: 'x86_64_v2-unknown-linux-gnu'
+            py: 'cpython-3.12'
+            options: 'pgo'
+            run: true
+          - target_triple: 'x86_64_v2-unknown-linux-gnu'
+            py: 'cpython-3.12'
+            options: 'pgo+lto'
+            run: true
+
+          - target_triple: 'x86_64_v3-unknown-linux-gnu'
+            py: 'cpython-3.9'
+            options: 'debug'
+            run: true
+          - target_triple: 'x86_64_v3-unknown-linux-gnu'
+            py: 'cpython-3.9'
+            options: 'pgo'
+            run: true
+          - target_triple: 'x86_64_v3-unknown-linux-gnu'
+            py: 'cpython-3.9'
+            options: 'pgo+lto'
+            run: true
+
+          - target_triple: 'x86_64_v3-unknown-linux-gnu'
+            py: 'cpython-3.10'
+            options: 'debug'
+            run: true
+          - target_triple: 'x86_64_v3-unknown-linux-gnu'
+            py: 'cpython-3.10'
+            options: 'pgo'
+            run: true
+          - target_triple: 'x86_64_v3-unknown-linux-gnu'
+            py: 'cpython-3.10'
+            options: 'pgo+lto'
+            run: true
+
+          - target_triple: 'x86_64_v3-unknown-linux-gnu'
+            py: 'cpython-3.11'
+            options: 'debug'
+            run: true
+          - target_triple: 'x86_64_v3-unknown-linux-gnu'
+            py: 'cpython-3.11'
+            options: 'pgo'
+            run: true
+          - target_triple: 'x86_64_v3-unknown-linux-gnu'
+            py: 'cpython-3.11'
+            options: 'pgo+lto'
+            run: true
+
+          - target_triple: 'x86_64_v3-unknown-linux-gnu'
+            py: 'cpython-3.12'
+            options: 'debug'
+            run: true
+          - target_triple: 'x86_64_v3-unknown-linux-gnu'
+            py: 'cpython-3.12'
+            options: 'pgo'
+            run: true
+          - target_triple: 'x86_64_v3-unknown-linux-gnu'
+            py: 'cpython-3.12'
+            options: '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'
+            options: 'debug'
+          - target_triple: 'x86_64_v4-unknown-linux-gnu'
+            py: 'cpython-3.9'
+            options: 'noopt'
+          - target_triple: 'x86_64_v4-unknown-linux-gnu'
+            py: 'cpython-3.9'
+            options: 'lto'
+
+          # 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.10'
+            options: 'debug'
+          - target_triple: 'x86_64_v4-unknown-linux-gnu'
+            py: 'cpython-3.10'
+            options: 'noopt'
+          - target_triple: 'x86_64_v4-unknown-linux-gnu'
+            py: 'cpython-3.10'
+            options: 'lto'
+
+          - target_triple: 'x86_64_v4-unknown-linux-gnu'
+            py: 'cpython-3.11'
+            options: 'debug'
+          - target_triple: 'x86_64_v4-unknown-linux-gnu'
+            py: 'cpython-3.11'
+            options: 'noopt'
+          - target_triple: 'x86_64_v4-unknown-linux-gnu'
+            py: 'cpython-3.11'
+            options: 'lto'
+
+          - target_triple: 'x86_64_v4-unknown-linux-gnu'
+            py: 'cpython-3.12'
+            options: 'debug'
+          - target_triple: 'x86_64_v4-unknown-linux-gnu'
+            py: 'cpython-3.12'
+            options: 'noopt'
+          - target_triple: 'x86_64_v4-unknown-linux-gnu'
+            py: 'cpython-3.12'
+            options: 'lto'
+
+          # musl doesn't support PGO.
+
+          - target_triple: 'x86_64-unknown-linux-musl'
+            py: 'cpython-3.9'
+            options: 'debug'
+            run: true
+          - target_triple: 'x86_64-unknown-linux-musl'
+            py: 'cpython-3.9'
+            options: 'noopt'
+            run: true
+          - target_triple: 'x86_64-unknown-linux-musl'
+            py: 'cpython-3.9'
+            options: 'lto'
+            run: true
+
+          - target_triple: 'x86_64-unknown-linux-musl'
+            py: 'cpython-3.10'
+            options: 'debug'
+            run: true
+          - target_triple: 'x86_64-unknown-linux-musl'
+            py: 'cpython-3.10'
+            options: 'noopt'
+            run: true
+          - target_triple: 'x86_64-unknown-linux-musl'
+            py: 'cpython-3.10'
+            options: 'lto'
+            run: true
+
+          - target_triple: 'x86_64-unknown-linux-musl'
+            py: 'cpython-3.11'
+            options: 'debug'
+            run: true
+          - target_triple: 'x86_64-unknown-linux-musl'
+            py: 'cpython-3.11'
+            options: 'noopt'
+            run: true
+          - target_triple: 'x86_64-unknown-linux-musl'
+            py: 'cpython-3.11'
+            options: 'lto'
+            run: true
+
+          - target_triple: 'x86_64-unknown-linux-musl'
+            py: 'cpython-3.12'
+            options: 'debug'
+            run: true
+          - target_triple: 'x86_64-unknown-linux-musl'
+            py: 'cpython-3.12'
+            options: 'noopt'
+            run: true
+          - target_triple: 'x86_64-unknown-linux-musl'
+            py: 'cpython-3.12'
+            options: 'lto'
+            run: true
+
+          - target_triple: 'x86_64_v2-unknown-linux-musl'
+            py: 'cpython-3.9'
+            options: 'debug'
+            run: true
+          - target_triple: 'x86_64_v2-unknown-linux-musl'
+            py: 'cpython-3.9'
+            options: 'noopt'
+            run: true
+          - target_triple: 'x86_64_v2-unknown-linux-musl'
+            py: 'cpython-3.9'
+            options: 'lto'
+            run: true
+
+          - target_triple: 'x86_64_v2-unknown-linux-musl'
+            py: 'cpython-3.10'
+            options: 'debug'
+            run: true
+          - target_triple: 'x86_64_v2-unknown-linux-musl'
+            py: 'cpython-3.10'
+            options: 'noopt'
+            run: true
+          - target_triple: 'x86_64_v2-unknown-linux-musl'
+            py: 'cpython-3.10'
+            options: 'lto'
+            run: true
+
+          - target_triple: 'x86_64_v2-unknown-linux-musl'
+            py: 'cpython-3.11'
+            options: 'debug'
+            run: true
+          - target_triple: 'x86_64_v2-unknown-linux-musl'
+            py: 'cpython-3.11'
+            options: 'noopt'
+            run: true
+          - target_triple: 'x86_64_v2-unknown-linux-musl'
+            py: 'cpython-3.11'
+            options: 'lto'
+            run: true
+
+          - target_triple: 'x86_64_v2-unknown-linux-musl'
+            py: 'cpython-3.12'
+            options: 'debug'
+            run: true
+          - target_triple: 'x86_64_v2-unknown-linux-musl'
+            py: 'cpython-3.12'
+            options: 'noopt'
+            run: true
+          - target_triple: 'x86_64_v2-unknown-linux-musl'
+            py: 'cpython-3.12'
+            options: 'lto'
+            run: true
+
+          - target_triple: 'x86_64_v3-unknown-linux-musl'
+            py: 'cpython-3.9'
+            options: 'debug'
+            run: true
+          - target_triple: 'x86_64_v3-unknown-linux-musl'
+            py: 'cpython-3.9'
+            options: 'noopt'
+            run: true
+          - target_triple: 'x86_64_v3-unknown-linux-musl'
+            py: 'cpython-3.9'
+            options: 'lto'
+            run: true
+
+          - target_triple: 'x86_64_v3-unknown-linux-musl'
+            py: 'cpython-3.10'
+            options: 'debug'
+            run: true
+          - target_triple: 'x86_64_v3-unknown-linux-musl'
+            py: 'cpython-3.10'
+            options: 'noopt'
+            run: true
+          - target_triple: 'x86_64_v3-unknown-linux-musl'
+            py: 'cpython-3.10'
+            options: 'lto'
+            run: true
+
+          - target_triple: 'x86_64_v3-unknown-linux-musl'
+            py: 'cpython-3.11'
+            options: 'debug'
+            run: true
+          - target_triple: 'x86_64_v3-unknown-linux-musl'
+            py: 'cpython-3.11'
+            options: 'noopt'
+            run: true
+          - target_triple: 'x86_64_v3-unknown-linux-musl'
+            py: 'cpython-3.11'
+            options: 'lto'
+            run: true
+
+          - target_triple: 'x86_64_v3-unknown-linux-musl'
+            py: 'cpython-3.12'
+            options: 'debug'
+            run: true
+          - target_triple: 'x86_64_v3-unknown-linux-musl'
+            py: 'cpython-3.12'
+            options: 'noopt'
+            run: true
+          - target_triple: 'x86_64_v3-unknown-linux-musl'
+            py: 'cpython-3.12'
+            options: 'lto'
+            run: true
+
+          - target_triple: 'x86_64_v4-unknown-linux-musl'
+            py: 'cpython-3.9'
+            options: 'debug'
+          - target_triple: 'x86_64_v4-unknown-linux-musl'
+            py: 'cpython-3.9'
+            options: 'noopt'
+          - target_triple: 'x86_64_v4-unknown-linux-musl'
+            py: 'cpython-3.9'
+            options: 'lto'
+
+          - target_triple: 'x86_64_v4-unknown-linux-musl'
+            py: 'cpython-3.10'
+            options: 'debug'
+          - target_triple: 'x86_64_v4-unknown-linux-musl'
+            py: 'cpython-3.10'
+            options: 'noopt'
+          - target_triple: 'x86_64_v4-unknown-linux-musl'
+            py: 'cpython-3.10'
+            options: 'lto'
+
+          - target_triple: 'x86_64_v4-unknown-linux-musl'
+            py: 'cpython-3.11'
+            options: 'debug'
+          - target_triple: 'x86_64_v4-unknown-linux-musl'
+            py: 'cpython-3.11'
+            options: 'noopt'
+          - target_triple: 'x86_64_v4-unknown-linux-musl'
+            py: 'cpython-3.11'
+            options: 'lto'
+
+          - target_triple: 'x86_64_v4-unknown-linux-musl'
+            py: 'cpython-3.12'
+            options: 'debug'
+          - target_triple: 'x86_64_v4-unknown-linux-musl'
+            py: 'cpython-3.12'
+            options: 'noopt'
+          - target_triple: 'x86_64_v4-unknown-linux-musl'
+            py: 'cpython-3.12'
+            options: 'lto'
 
     needs:
       - pythonbuild
@@ -214,10 +796,293 @@ jobs:
       fail-fast: false
       matrix:
         build:
+
+          - target_triple: 'aarch64-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'debug'
+          - target_triple: 'aarch64-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'noopt'
+          - target_triple: 'aarch64-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'lto'
+          - target_triple: 'aarch64-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'freethreaded+debug'
+          - target_triple: 'aarch64-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'freethreaded+noopt'
+          - target_triple: 'aarch64-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'freethreaded+lto'
+
+          - target_triple: 'armv7-unknown-linux-gnueabi'
+            py: 'cpython-3.13'
+            options: 'debug'
+          - target_triple: 'armv7-unknown-linux-gnueabi'
+            py: 'cpython-3.13'
+            options: 'noopt'
+          - target_triple: 'armv7-unknown-linux-gnueabi'
+            py: 'cpython-3.13'
+            options: 'lto'
+          - target_triple: 'armv7-unknown-linux-gnueabi'
+            py: 'cpython-3.13'
+            options: 'freethreaded+debug'
+          - target_triple: 'armv7-unknown-linux-gnueabi'
+            py: 'cpython-3.13'
+            options: 'freethreaded+noopt'
+          - target_triple: 'armv7-unknown-linux-gnueabi'
+            py: 'cpython-3.13'
+            options: 'freethreaded+lto'
+
+          - target_triple: 'armv7-unknown-linux-gnueabihf'
+            py: 'cpython-3.13'
+            options: 'debug'
+          - target_triple: 'armv7-unknown-linux-gnueabihf'
+            py: 'cpython-3.13'
+            options: 'noopt'
+          - target_triple: 'armv7-unknown-linux-gnueabihf'
+            py: 'cpython-3.13'
+            options: 'lto'
+          - target_triple: 'armv7-unknown-linux-gnueabihf'
+            py: 'cpython-3.13'
+            options: 'freethreaded+debug'
+          - target_triple: 'armv7-unknown-linux-gnueabihf'
+            py: 'cpython-3.13'
+            options: 'freethreaded+noopt'
+          - target_triple: 'armv7-unknown-linux-gnueabihf'
+            py: 'cpython-3.13'
+            options: 'freethreaded+lto'
+
+          - target_triple: 's390x-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'debug'
+          - target_triple: 's390x-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'noopt'
+          - target_triple: 's390x-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'lto'
+          - target_triple: 's390x-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'freethreaded+debug'
+          - target_triple: 's390x-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'freethreaded+noopt'
+          - target_triple: 's390x-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'freethreaded+lto'
+
+          - target_triple: 'ppc64le-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'debug'
+          - target_triple: 'ppc64le-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'noopt'
+          - target_triple: 'ppc64le-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'lto'
+          - target_triple: 'ppc64le-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'freethreaded+debug'
+          - target_triple: 'ppc64le-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'freethreaded+noopt'
+          - target_triple: 'ppc64le-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'freethreaded+lto'
+
+          - target_triple: 'x86_64-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'debug'
+            run: true
+          - target_triple: 'x86_64-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'pgo'
+            run: true
+          - target_triple: 'x86_64-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'pgo+lto'
+            run: true
+          - target_triple: 'x86_64-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'freethreaded+debug'
+            run: true
           - target_triple: 'x86_64-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'freethreaded+pgo'
+            run: true
+          - target_triple: 'x86_64-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'freethreaded+pgo+lto'
+            run: true
+
+          - target_triple: 'x86_64_v2-unknown-linux-gnu'
             py: 'cpython-3.13'
             options: 'debug'
             run: true
+          - target_triple: 'x86_64_v2-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'pgo'
+            run: true
+          - target_triple: 'x86_64_v2-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'pgo+lto'
+            run: true
+          - target_triple: 'x86_64_v2-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'freethreaded+debug'
+            run: true
+          - target_triple: 'x86_64_v2-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'freethreaded+pgo'
+            run: true
+          - target_triple: 'x86_64_v2-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'freethreaded+pgo+lto'
+            run: true
+
+          - target_triple: 'x86_64_v3-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'debug'
+            run: true
+          - target_triple: 'x86_64_v3-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'pgo'
+            run: true
+          - target_triple: 'x86_64_v3-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'pgo+lto'
+            run: true
+          - target_triple: 'x86_64_v3-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'freethreaded+debug'
+            run: true
+          - target_triple: 'x86_64_v3-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'freethreaded+pgo'
+            run: true
+          - target_triple: 'x86_64_v3-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'freethreaded+pgo+lto'
+            run: true
+
+          - target_triple: 'x86_64-unknown-linux-musl'
+            py: 'cpython-3.13'
+            options: 'debug'
+            run: true
+          - target_triple: 'x86_64-unknown-linux-musl'
+            py: 'cpython-3.13'
+            options: 'noopt'
+            run: true
+          - target_triple: 'x86_64-unknown-linux-musl'
+            py: 'cpython-3.13'
+            options: 'lto'
+            run: true
+          # TODO: Free-threaded musl builds are blocked by upgrading LLVM 14 -> 18.
+          # - target_triple: 'x86_64-unknown-linux-musl'
+          #   py: 'cpython-3.13'
+          #   options: 'freethreaded+debug'
+          #   run: true
+          # - target_triple: 'x86_64-unknown-linux-musl'
+          #   py: 'cpython-3.13'
+          #   options: 'freethreaded+noopt'
+          #   run: true
+          # - target_triple: 'x86_64-unknown-linux-musl'
+          #   py: 'cpython-3.13'
+          #   options: 'freethreaded+lto'
+          #   run: true
+
+          - target_triple: 'x86_64_v2-unknown-linux-musl'
+            py: 'cpython-3.13'
+            options: 'debug'
+            run: true
+          - target_triple: 'x86_64_v2-unknown-linux-musl'
+            py: 'cpython-3.13'
+            options: 'noopt'
+            run: true
+          - target_triple: 'x86_64_v2-unknown-linux-musl'
+            py: 'cpython-3.13'
+            options: 'lto'
+            run: true
+          # TODO: Free-threaded musl builds are blocked by upgrading LLVM 14 -> 18.
+          # - target_triple: 'x86_64_v2-unknown-linux-musl'
+          #   py: 'cpython-3.13'
+          #   options: 'freethreaded+debug'
+          #   run: true
+          # - target_triple: 'x86_64_v2-unknown-linux-musl'
+          #   py: 'cpython-3.13'
+          #   options: 'freethreaded+noopt'
+          #   run: true
+          # - target_triple: 'x86_64_v2-unknown-linux-musl'
+          #   py: 'cpython-3.13'
+          #   options: 'freethreaded+lto'
+          #   run: true
+
+          - target_triple: 'x86_64_v4-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'debug'
+          - target_triple: 'x86_64_v4-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'noopt'
+          - target_triple: 'x86_64_v4-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'lto'
+          - target_triple: 'x86_64_v4-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'freethreaded+debug'
+          - target_triple: 'x86_64_v4-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'freethreaded+noopt'
+          - target_triple: 'x86_64_v4-unknown-linux-gnu'
+            py: 'cpython-3.13'
+            options: 'freethreaded+lto'
+
+          - target_triple: 'x86_64_v3-unknown-linux-musl'
+            py: 'cpython-3.13'
+            options: 'debug'
+            run: true
+          - target_triple: 'x86_64_v3-unknown-linux-musl'
+            py: 'cpython-3.13'
+            options: 'noopt'
+            run: true
+          - target_triple: 'x86_64_v3-unknown-linux-musl'
+            py: 'cpython-3.13'
+            options: 'lto'
+            run: true
+          # TODO: Free-threaded musl builds are blocked by upgrading LLVM 14 -> 18.
+          # - target_triple: 'x86_64_v3-unknown-linux-musl'
+          #   py: 'cpython-3.13'
+          #   options: 'freethreaded+debug'
+          #   run: true
+          # - target_triple: 'x86_64_v3-unknown-linux-musl'
+          #   py: 'cpython-3.13'
+          #   options: 'freethreaded+noopt'
+          #   run: true
+          # - target_triple: 'x86_64_v3-unknown-linux-musl'
+          #   py: 'cpython-3.13'
+          #   options: 'freethreaded+lto'
+          #   run: true
+
+          - target_triple: 'x86_64_v4-unknown-linux-musl'
+            py: 'cpython-3.13'
+            options: 'debug'
+          - target_triple: 'x86_64_v4-unknown-linux-musl'
+            py: 'cpython-3.13'
+            options: 'noopt'
+          - target_triple: 'x86_64_v4-unknown-linux-musl'
+            py: 'cpython-3.13'
+            options: 'lto'
+          # TODO: Free-threaded musl builds are blocked by upgrading LLVM 14 -> 18.
+          # - target_triple: 'x86_64_v4-unknown-linux-musl'
+          #   py: 'cpython-3.13'
+          #   options: 'freethreaded+debug'
+          # - target_triple: 'x86_64_v4-unknown-linux-musl'
+          #   py: 'cpython-3.13'
+          #   options: 'freethreaded+noopt'
+          # - target_triple: 'x86_64_v4-unknown-linux-musl'
+          #   py: 'cpython-3.13'
+          #   options: 'freethreaded+lto'
 
     needs:
       - pythonbuild
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
new file mode 100644
index 00000000..18b83895
--- /dev/null
+++ b/.github/workflows/windows.yml
@@ -0,0 +1,110 @@
+name: Windows Python build
+
+on:
+  push:
+    branches: [main]
+  pull_request:
+
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.sha }}
+  cancel-in-progress: ${{ github.event_name == 'pull_request' }}
+
+env:
+  FORCE_COLOR: 1
+
+jobs:
+  pythonbuild:
+    runs-on: 'windows-2022'
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Emit rustc version
+        run: |
+          rustc --version > .rustc-version
+
+      - uses: actions/cache@v4
+        with:
+          path: |
+            C:/Rust/.cargo/registry
+            C:/Rust/.cargo/git
+            target
+          key: ${{ runner.os }}-pythonbuild-${{ hashFiles('Cargo.lock', '.rustc-version') }}
+
+      - name: Build
+        run: |
+          cargo build --release
+
+      - name: Upload executable
+        uses: actions/upload-artifact@v4
+        with:
+          name: pythonbuild
+          path: target/release/pythonbuild.exe
+
+  build:
+    strategy:
+      fail-fast: false
+      matrix:
+        py:
+          - 'cpython-3.9'
+          - 'cpython-3.10'
+          - 'cpython-3.11'
+          - 'cpython-3.12'
+          - 'cpython-3.13'
+        vcvars:
+          - 'vcvars32.bat'
+          - 'vcvars64.bat'
+        options:
+          - 'pgo'
+
+        include:
+          - py: 'cpython-3.13'
+            vcvars: 'vcvars32.bat'
+            options: 'freethreaded+pgo'
+          - py: 'cpython-3.13'
+            vcvars: 'vcvars64.bat'
+            options: 'freethreaded+pgo'
+
+    needs: pythonbuild
+    runs-on: 'windows-2022'
+    steps:
+      - uses: actions/checkout@v4
+        with:
+          fetch-depth: 0
+
+      - name: Install Cygwin Environment
+        uses: cygwin/cygwin-install-action@49f298a7ebb00d4b3ddf58000c3e78eff5fbd6b9
+        with:
+          packages: autoconf automake libtool
+
+      - name: Install Python
+        uses: actions/setup-python@v5
+        with:
+          python-version: '3.11'
+
+      - name: Download pythonbuild Executable
+        uses: actions/download-artifact@v4
+        with:
+          name: pythonbuild
+
+      # We need to do this before we activate the VC++ environment or else binary packages
+      # don't get compiled properly.
+      - name: Bootstrap Python environment
+        run: |
+          py.exe -3.9 build-windows.py --help
+
+      - name: Build
+        shell: cmd
+        run: |
+          call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\${{ matrix.vcvars }}"
+          py.exe -3.9 build-windows.py --python ${{ matrix.py }} --sh c:\cygwin\bin\sh.exe --options ${{ matrix.options }}
+
+      - name: Validate Distribution
+        run: |
+          $Dists = Resolve-Path -Path "dist/*.tar.zst" -Relative
+          .\pythonbuild.exe validate-distribution --run $Dists
+
+      - name: Upload Distributions
+        uses: actions/upload-artifact@v4
+        with:
+          name: ${{ matrix.py }}-${{ matrix.vcvars }}-${{ matrix.options }}
+          path: dist/*
diff --git a/build-macos.py b/build-macos.py
index d2d8cd84..0061fc13 100755
--- a/build-macos.py
+++ b/build-macos.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.12
+#!/usr/bin/env python3
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at https://mozilla.org/MPL/2.0/.