diff --git a/packages/python/cpython-windows-externals.patch b/packages/python/cpython-windows-externals.patch
new file mode 100644
index 0000000000000000000000000000000000000000..c3bcce983f0ea58112ca6efca38c6e4677d78de2
--- /dev/null
+++ b/packages/python/cpython-windows-externals.patch
@@ -0,0 +1,28 @@
+diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat
+index b5a44e3..52941c7 100644
+--- a/PCbuild/get_externals.bat
++++ b/PCbuild/get_externals.bat
+@@ -76,7 +76,7 @@ for %%e in (%libraries%) do (
+ echo.Fetching external binaries...
+ 
+ set binaries=
+-if NOT "%IncludeLibffi%"=="false"  set binaries=%binaries% libffi
++if NOT "%IncludeLibffi%"=="false"  set binaries=%binaries% libffi-3.3.0
+ if NOT "%IncludeSSL%"=="false"     set binaries=%binaries% openssl-bin-1.1.1k-1
+ if NOT "%IncludeTkinter%"=="false" set binaries=%binaries% tcltk-8.6.9.0
+ if NOT "%IncludeSSLSrc%"=="false"  set binaries=%binaries% nasm-2.11.06
+diff --git a/PCbuild/python.props b/PCbuild/python.props
+index 419d5eb..c66fb07 100644
+--- a/PCbuild/python.props
++++ b/PCbuild/python.props
+@@ -59,8 +59,8 @@
+     <sqlite3Dir>$(ExternalsDir)sqlite-3.35.5.0\</sqlite3Dir>
+     <bz2Dir>$(ExternalsDir)bzip2-1.0.6\</bz2Dir>
+     <lzmaDir>$(ExternalsDir)xz-5.2.2\</lzmaDir>
+-    <libffiDir>$(ExternalsDir)libffi\</libffiDir>
+-    <libffiOutDir>$(ExternalsDir)libffi\$(ArchName)\</libffiOutDir>
++    <libffiDir>$(ExternalsDir)libffi-3.3.0\</libffiDir>
++    <libffiOutDir>$(ExternalsDir)libffi-3.3.0\$(ArchName)\</libffiOutDir>
+     <libffiIncludeDir>$(libffiOutDir)include</libffiIncludeDir>
+     <opensslDir>$(ExternalsDir)openssl-1.1.1k\</opensslDir>
+     <opensslOutDir>$(ExternalsDir)openssl-bin-1.1.1k-1\$(ArchName)\</opensslOutDir>
diff --git a/packages/python/fj-rpath-3.1.patch b/packages/python/fj-rpath-3.1.patch
new file mode 100644
index 0000000000000000000000000000000000000000..d25b58da77f6e2fda67d3fd5402d326382d9ab43
--- /dev/null
+++ b/packages/python/fj-rpath-3.1.patch
@@ -0,0 +1,13 @@
+--- a/Lib/distutils/unixccompiler.py	2009-05-09 21:55:12.000000000 +1000
++++ b/Lib/distutils/unixccompiler.py	2017-05-13 14:30:18.077518999 +1000
+@@ -215,7 +211,8 @@
+         return "-L" + dir
+
+     def _is_gcc(self, compiler_name):
+-        return "gcc" in compiler_name or "g++" in compiler_name
++        return "gcc" in compiler_name or "g++" in compiler_name \
++        or "fcc" in compiler_name or "FCC" in compiler_name
+
+     def runtime_library_dir_option(self, dir):
+         # XXX Hackish, at the very least.  See Python bug #445902:
+
diff --git a/packages/python/fj-rpath-3.9.patch b/packages/python/fj-rpath-3.9.patch
new file mode 100644
index 0000000000000000000000000000000000000000..1542b367e94257d46a39a59c903fdb46095e34ab
--- /dev/null
+++ b/packages/python/fj-rpath-3.9.patch
@@ -0,0 +1,11 @@
+--- spack-src/Lib/distutils/unixccompiler.py.org	2022-01-31 14:42:34.000000000 +0900
++++ spack-src/Lib/distutils/unixccompiler.py	2022-01-31 14:43:19.000000000 +0900
+@@ -212,7 +212,7 @@
+ 
+     def _is_gcc(self, compiler_name):
+         # clang uses same syntax for rpath as gcc
+-        return any(name in compiler_name for name in ("gcc", "g++", "clang"))
++        return any(name in compiler_name for name in ("gcc", "g++", "clang", "fcc", "FCC"))
+ 
+     def runtime_library_dir_option(self, dir):
+         # XXX Hackish, at the very least.  See Python bug #445902:
diff --git a/packages/python/intel-3.7.patch b/packages/python/intel-3.7.patch
new file mode 100644
index 0000000000000000000000000000000000000000..f2277624af27a7567fc73bed8211809e283ee88d
--- /dev/null
+++ b/packages/python/intel-3.7.patch
@@ -0,0 +1,38 @@
+From 87ed388f41d761ddddc8447e5104569f2436c005 Mon Sep 17 00:00:00 2001
+From: Victor Stinner <vstinner@python.org>
+Date: Fri, 11 Oct 2019 15:13:51 +0200
+Subject: [PATCH] bpo-37415: Fix stdatomic.h header check for ICC compiler
+
+Fix stdatomic.h header check for ICC compiler: the ICC implementation
+lacks atomic_uintptr_t type which is needed by Python.
+
+Test:
+
+* atomic_int and atomic_uintptr_t types
+* atomic_load_explicit() and atomic_store_explicit()
+* memory_order_relaxed and memory_order_seq_cst constants
+
+But don't test ATOMIC_VAR_INIT(): it's not used in Python.
+---
+ configure                                     | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/configure b/configure
+index f1979c1b8124c..1b30a848a77e7 100755
+--- a/configure
++++ b/configure
+@@ -16734,9 +16722,12 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ 
+ 
+     #include <stdatomic.h>
+-    atomic_int value = ATOMIC_VAR_INIT(1);
++    atomic_int int_var;
++    atomic_uintptr_t uintptr_var;
+     int main() {
+-      int loaded_value = atomic_load(&value);
++      atomic_store_explicit(&int_var, 5, memory_order_relaxed);
++      atomic_store_explicit(&uintptr_var, 0, memory_order_relaxed);
++      int loaded_value = atomic_load_explicit(&int_var, memory_order_seq_cst);
+       return 0;
+     }
+ 
diff --git a/packages/python/package.py b/packages/python/package.py
new file mode 100644
index 0000000000000000000000000000000000000000..3bfdc240d0481ccd791b36b8ee215bc707ab3ee6
--- /dev/null
+++ b/packages/python/package.py
@@ -0,0 +1,1318 @@
+# Copyright 2013-2024 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import glob
+import json
+import os
+import platform
+import re
+import subprocess
+import sys
+from shutil import copy
+from typing import Dict, List
+
+import llnl.util.tty as tty
+from llnl.util.lang import dedupe
+
+from spack.build_environment import dso_suffix, stat_suffix
+from spack.package import *
+from spack.util.prefix import Prefix
+
+
+def make_pyvenv_cfg(python_spec: "spack.spec.Spec", venv_prefix: str) -> str:
+    """Make a pyvenv_cfg file for a given (real) python command and venv prefix."""
+    python_cmd = python_spec.command.path
+    lines = [
+        # directory containing python command
+        f"home = {os.path.dirname(python_cmd)}",
+        # venv should not allow site packages from the real python to be loaded
+        "include-system-site-packages = false",
+        # version of the python command
+        f"version = {python_spec.version}",
+        # the path to the python command
+        f"executable = {python_cmd}",
+        # command "used" to create the pyvenv.cfg
+        f"command = {python_cmd} -m venv --without-pip {venv_prefix}",
+    ]
+
+    return "\n".join(lines) + "\n"
+
+
+class Python(Package):
+    """The Python programming language."""
+
+    homepage = "https://www.python.org/"
+    url = "https://www.python.org/ftp/python/3.8.0/Python-3.8.0.tgz"
+    list_url = "https://www.python.org/ftp/python/"
+    list_depth = 1
+    tags = ["windows"]
+
+    maintainers("skosukhin", "scheibelp")
+
+    phases = ["configure", "build", "install"]
+
+    #: phase
+    install_targets = ["install"]
+    build_targets: List[str] = []
+
+    license("0BSD")
+
+    version("3.13.0", sha256="12445c7b3db3126c41190bfdc1c8239c39c719404e844babbd015a1bc3fafcd4")
+    version("3.12.5", sha256="38dc4e2c261d49c661196066edbfb70fdb16be4a79cc8220c224dfeb5636d405")
+    version("3.12.4", sha256="01b3c1c082196f3b33168d344a9c85fb07bfe0e7ecfe77fee4443420d1ce2ad9")
+    version("3.12.3", sha256="a6b9459f45a6ebbbc1af44f5762623fa355a0c87208ed417628b379d762dddb0")
+    version("3.12.2", sha256="a7c4f6a9dc423d8c328003254ab0c9338b83037bd787d680826a5bf84308116e")
+    version("3.12.1", sha256="d01ec6a33bc10009b09c17da95cc2759af5a580a7316b3a446eb4190e13f97b2")
+    version("3.12.0", sha256="51412956d24a1ef7c97f1cb5f70e185c13e3de1f50d131c0aac6338080687afb")
+    version("3.11.9", sha256="e7de3240a8bc2b1e1ba5c81bf943f06861ff494b69fda990ce2722a504c6153d")
+    version("3.11.8", sha256="d3019a613b9e8761d260d9ebe3bd4df63976de30464e5c0189566e1ae3f61889")
+    version("3.11.7", sha256="068c05f82262e57641bd93458dfa883128858f5f4997aad7a36fd25b13b29209")
+    version("3.11.6", sha256="c049bf317e877cbf9fce8c3af902436774ecef5249a29d10984ca3a37f7f4736")
+    version("3.11.5", sha256="a12a0a013a30b846c786c010f2c19dd36b7298d888f7c4bd1581d90ce18b5e58")
+    version("3.11.4", sha256="85c37a265e5c9dd9f75b35f954e31fbfc10383162417285e30ad25cc073a0d63")
+    version("3.11.3", sha256="1a79f3df32265d9e6625f1a0b31c28eb1594df911403d11f3320ee1da1b3e048")
+    version("3.11.2", sha256="2411c74bda5bbcfcddaf4531f66d1adc73f247f529aee981b029513aefdbf849")
+    version("3.11.1", sha256="baed518e26b337d4d8105679caf68c5c32630d702614fc174e98cb95c46bdfa4")
+    version("3.11.0", sha256="64424e96e2457abbac899b90f9530985b51eef2905951febd935f0e73414caeb")
+    version("3.10.14", sha256="cefea32d3be89c02436711c95a45c7f8e880105514b78680c14fe76f5709a0f6")
+    version("3.10.13", sha256="698ec55234c1363bd813b460ed53b0f108877c7a133d48bde9a50a1eb57b7e65")
+    version("3.10.12", sha256="a43cd383f3999a6f4a7db2062b2fc9594fefa73e175b3aedafa295a51a7bb65c")
+    version("3.10.11", sha256="f3db31b668efa983508bd67b5712898aa4247899a346f2eb745734699ccd3859")
+    version("3.10.10", sha256="fba64559dde21ebdc953e4565e731573bb61159de8e4d4cedee70fb1196f610d")
+    version("3.10.9", sha256="4ccd7e46c8898f4c7862910a1703aa0e63525913a519abb2f55e26220a914d88")
+    version("3.10.8", sha256="f400c3fb394b8bef1292f6dc1292c5fadc3533039a5bc0c3e885f3e16738029a")
+    version("3.10.7", sha256="1b2e4e2df697c52d36731666979e648beeda5941d0f95740aafbf4163e5cc126")
+    version("3.10.6", sha256="848cb06a5caa85da5c45bd7a9221bb821e33fc2bdcba088c127c58fad44e6343")
+    version("3.10.5", sha256="18f57182a2de3b0be76dfc39fdcfd28156bb6dd23e5f08696f7492e9e3d0bf2d")
+    version("3.10.4", sha256="f3bcc65b1d5f1dc78675c746c98fcee823c038168fc629c5935b044d0911ad28")
+    version("3.10.3", sha256="5a3b029bad70ba2a019ebff08a65060a8b9b542ffc1a83c697f1449ecca9813b")
+    version("3.10.2", sha256="3c0ede893011319f9b0a56b44953a3d52c7abf9657c23fb4bc9ced93b86e9c97")
+    version("3.10.1", sha256="b76117670e7c5064344b9c138e141a377e686b9063f3a8a620ff674fa8ec90d3")
+    version("3.10.0", sha256="c4e0cbad57c90690cb813fb4663ef670b4d0f587d8171e2c42bd4c9245bd2758")
+    version("3.9.19", sha256="f5f9ec8088abca9e399c3b62fd8ef31dbd2e1472c0ccb35070d4d136821aaf71")
+    version("3.9.18", sha256="504ce8cfd59addc04c22f590377c6be454ae7406cb1ebf6f5a350149225a9354")
+    version("3.9.17", sha256="8ead58f669f7e19d777c3556b62fae29a81d7f06a7122ff9bc57f7dd82d7e014")
+    version("3.9.16", sha256="1ad539e9dbd2b42df714b69726e0693bc6b9d2d2c8e91c2e43204026605140c5")
+    version("3.9.15", sha256="48d1ccb29d5fbaf1fb8f912271d09f7450e426d4dfe95978ef6aaada70ece4d8")
+    version("3.9.14", sha256="9201836e2c16361b2b7408680502393737d44f227333fe2e5729c7d5f6041675")
+    version("3.9.13", sha256="829b0d26072a44689a6b0810f5b4a3933ee2a0b8a4bfc99d7c5893ffd4f97c44")
+    version("3.9.12", sha256="70e08462ebf265012bd2be88a63d2149d880c73e53f1712b7bbbe93750560ae8")
+    version("3.9.11", sha256="3442400072f582ac2f0df30895558f08883b416c8c7877ea55d40d00d8a93112")
+    version("3.9.10", sha256="1aa9c0702edbae8f6a2c95f70a49da8420aaa76b7889d3419c186bfc8c0e571e")
+    version("3.9.9", sha256="2cc7b67c1f3f66c571acc42479cdf691d8ed6b47bee12c9b68430413a17a44ea")
+    version("3.9.8", sha256="7447fb8bb270942d620dd24faa7814b1383b61fa99029a240025fd81c1db8283")
+    version("3.9.7", sha256="a838d3f9360d157040142b715db34f0218e535333696a5569dc6f854604eb9d1")
+    version("3.9.6", sha256="d0a35182e19e416fc8eae25a3dcd4d02d4997333e4ad1f2eee6010aadc3fe866")
+    version("3.9.5", sha256="e0fbd5b6e1ee242524430dee3c91baf4cbbaba4a72dd1674b90fda87b713c7ab")
+    version("3.9.4", sha256="66c4de16daa74a825cf9da9ddae1fe020b72c3854b73b1762011cc33f9e4592f")
+    version("3.9.3", sha256="3afeb61a45b5a2e6f1c0f621bd8cf925a4ff406099fdb3d8c97b993a5f43d048")
+    version("3.9.2", sha256="7899e8a6f7946748830d66739f2d8f2b30214dad956e56b9ba216b3de5581519")
+    version("3.9.1", sha256="29cb91ba038346da0bd9ab84a0a55a845d872c341a4da6879f462e94c741f117")
+    version("3.9.0", sha256="df796b2dc8ef085edae2597a41c1c0a63625ebd92487adaef2fed22b567873e8")
+    version("3.8.19", sha256="c7fa55a36e5c7a19ec37d8f90f60a2197548908c9ac8b31e7c0dbffdd470eeac")
+    version("3.8.18", sha256="7c5df68bab1be81a52dea0cc2e2705ea00553b67107a301188383d7b57320b16")
+    version("3.8.17", sha256="def428fa6cf61b66bcde72e3d9f7d07d33b2e4226f04f9d6fce8384c055113ae")
+    version("3.8.16", sha256="71ca9d935637ed2feb59e90a368361dc91eca472a90acb1d344a2e8178ccaf10")
+    version("3.8.15", sha256="924d46999df82aa2eaa1de5ca51d6800ffb56b4bf52486a28f40634e3362abc4")
+    version("3.8.14", sha256="41f959c480c59211feb55d5a28851a56c7e22d02ef91035606ebb21011723c31")
+    version("3.8.13", sha256="903b92d76354366b1d9c4434d0c81643345cef87c1600adfa36095d7b00eede4")
+    version("3.8.12", sha256="316aa33f3b7707d041e73f246efedb297a70898c4b91f127f66dc8d80c596f1a")
+    version("3.8.11", sha256="b77464ea80cec14581b86aeb7fb2ff02830e0abc7bcdc752b7b4bdfcd8f3e393")
+    version("3.8.10", sha256="b37ac74d2cbad2590e7cd0dd2b3826c29afe89a734090a87bf8c03c45066cb65")
+    version("3.8.9", sha256="9779ec1df000bf86914cdd40860b88da56c1e61db59d37784beca14a259ac9e9")
+    version("3.8.8", sha256="76c0763f048e4f9b861d24da76b7dd5c7a3ba7ec086f40caedeea359263276f7")
+    version("3.8.7", sha256="20e5a04262f0af2eb9c19240d7ec368f385788bba2d8dfba7e74b20bab4d2bac")
+    version("3.8.6", sha256="313562ee9986dc369cd678011bdfd9800ef62fbf7b1496228a18f86b36428c21")
+    version("3.8.5", sha256="015115023c382eb6ab83d512762fe3c5502fa0c6c52ffebc4831c4e1a06ffc49")
+    version("3.8.4", sha256="32c4d9817ef11793da4d0d95b3191c4db81d2e45544614e8449255ca9ae3cc18")
+    version("3.8.3", sha256="6af6d4d2e010f9655518d0fc6738c7ff7069f10a4d2fbd55509e467f092a8b90")
+    version("3.8.2", sha256="e634a7a74776c2b89516b2e013dda1728c89c8149b9863b8cea21946daf9d561")
+    version("3.8.1", sha256="c7cfa39a43b994621b245e029769e9126caa2a93571cee2e743b213cceac35fb")
+    version("3.8.0", sha256="f1069ad3cae8e7ec467aa98a6565a62a48ef196cb8f1455a245a08db5e1792df")
+    version(
+        "3.7.17",
+        sha256="fd50161bc2a04f4c22a0971ff0f3856d98b4bf294f89740a9f06b520aae63b49",
+        deprecated=True,
+    )
+    version(
+        "3.7.16",
+        sha256="0cf2da07fa464636755215415909e22eb1d058817af4824bc15af8390d05fb38",
+        deprecated=True,
+    )
+    version(
+        "3.7.15",
+        sha256="cf2993798ae8430f3af3a00d96d9fdf320719f4042f039380dca79967c25e436",
+        deprecated=True,
+    )
+    version(
+        "3.7.14",
+        sha256="82b2abf8978caa61a9011d166eede831b32de9cbebc0db8162900fa23437b709",
+        deprecated=True,
+    )
+    version(
+        "3.7.13",
+        sha256="e405417f50984bc5870c7e7a9f9aeb93e9d270f5ac67f667a0cd3a09439682b5",
+        deprecated=True,
+    )
+    version(
+        "3.7.12",
+        sha256="33b4daaf831be19219659466d12645f87ecec6eb21d4d9f9711018a7b66cce46",
+        deprecated=True,
+    )
+    version(
+        "3.7.11",
+        sha256="b4fba32182e16485d0a6022ba83c9251e6a1c14676ec243a9a07d3722cd4661a",
+        deprecated=True,
+    )
+    version(
+        "3.7.10",
+        sha256="c9649ad84dc3a434c8637df6963100b2e5608697f9ba56d82e3809e4148e0975",
+        deprecated=True,
+    )
+    version(
+        "3.7.9",
+        sha256="39b018bc7d8a165e59aa827d9ae45c45901739b0bbb13721e4f973f3521c166a",
+        deprecated=True,
+    )
+    version(
+        "3.7.8",
+        sha256="0e25835614dc221e3ecea5831b38fa90788b5389b99b675a751414c858789ab0",
+        deprecated=True,
+    )
+    version(
+        "3.7.7",
+        sha256="8c8be91cd2648a1a0c251f04ea0bb4c2a5570feb9c45eaaa2241c785585b475a",
+        deprecated=True,
+    )
+    version(
+        "3.7.6",
+        sha256="aeee681c235ad336af116f08ab6563361a0c81c537072c1b309d6e4050aa2114",
+        deprecated=True,
+    )
+    version(
+        "3.7.5",
+        sha256="8ecc681ea0600bbfb366f2b173f727b205bb825d93d2f0b286bc4e58d37693da",
+        deprecated=True,
+    )
+    version(
+        "3.7.4",
+        sha256="d63e63e14e6d29e17490abbe6f7d17afb3db182dbd801229f14e55f4157c4ba3",
+        deprecated=True,
+    )
+    version(
+        "3.7.3",
+        sha256="d62e3015f2f89c970ac52343976b406694931742fbde2fed8d1ce8ebb4e1f8ff",
+        deprecated=True,
+    )
+    version(
+        "3.7.2",
+        sha256="f09d83c773b9cc72421abba2c317e4e6e05d919f9bcf34468e192b6a6c8e328d",
+        deprecated=True,
+    )
+    version(
+        "3.7.1",
+        sha256="36c1b81ac29d0f8341f727ef40864d99d8206897be96be73dc34d4739c9c9f06",
+        deprecated=True,
+    )
+    version(
+        "3.7.0",
+        sha256="85bb9feb6863e04fb1700b018d9d42d1caac178559ffa453d7e6a436e259fd0d",
+        deprecated=True,
+    )
+
+    depends_on("c", type="build")  # generated
+    depends_on("cxx", type="build")  # generated
+
+    extendable = True
+
+    # Variants to avoid cyclical dependencies for concretizer
+    variant("libxml2", default=True, description="Use a gettext library build with libxml2")
+
+    variant(
+        "debug", default=False, description="debug build with extra checks (this is high overhead)"
+    )
+
+    variant("shared", default=True, description="Enable shared libraries")
+    variant("pic", default=True, description="Produce position-independent code (for shared libs)")
+    variant(
+        "optimizations",
+        default=False,
+        description="Enable expensive build-time optimizations, if available",
+    )
+    # See https://legacy.python.org/dev/peps/pep-0394/
+    variant(
+        "pythoncmd",
+        default=sys.platform != "win32",
+        description="Symlink 'python3' executable to 'python' (not PEP 394 compliant)",
+    )
+
+    # Optional Python modules
+    variant("readline", default=sys.platform != "win32", description="Build readline module")
+    variant("ssl", default=True, description="Build ssl module")
+    variant("sqlite3", default=True, description="Build sqlite3 module")
+    variant("dbm", default=True, description="Build dbm module")
+    variant("nis", default=False, description="Build nis module")
+    variant("zlib", default=True, description="Build zlib module")
+    variant("bz2", default=True, description="Build bz2 module")
+    variant("lzma", default=True, description="Build lzma module")
+    variant("pyexpat", default=True, description="Build pyexpat module")
+    variant("ctypes", default=True, description="Build ctypes module")
+    variant("tkinter", default=False, description="Build tkinter module")
+    variant("uuid", default=True, description="Build uuid module")
+    variant("tix", default=False, description="Build Tix module", when="+tkinter")
+    variant("crypt", default=True, description="Build crypt module", when="@:3.12 platform=linux")
+    variant("crypt", default=True, description="Build crypt module", when="@:3.12 platform=darwin")
+
+    if sys.platform != "win32":
+        depends_on("gmake", type="build")
+        depends_on("pkgconfig@0.9.0:", type="build")
+        depends_on("gettext +libxml2", when="+libxml2")
+        depends_on("gettext ~libxml2", when="~libxml2")
+
+        # Optional dependencies
+        # See detect_modules() in setup.py for details
+        depends_on("readline", when="+readline")
+        depends_on("ncurses", when="+readline")
+        depends_on("openssl", when="+ssl")
+        # https://docs.python.org/3/whatsnew/3.7.html#build-changes
+        depends_on("openssl@1.0.2:", when="+ssl")
+        # https://docs.python.org/3.10/whatsnew/3.10.html#build-changes
+        depends_on("openssl@1.1.1:", when="@3.10:+ssl")
+        depends_on("sqlite@3.0.8:", when="@:3.9+sqlite3")
+        # https://docs.python.org/3.10/whatsnew/3.10.html#build-changes
+        depends_on("sqlite@3.7.15:", when="@3.10:+sqlite3")
+        depends_on("gdbm", when="+dbm")  # alternatively ndbm or berkeley-db
+        depends_on("libnsl", when="+nis")
+        depends_on("zlib-api", when="+zlib")
+        depends_on("bzip2", when="+bz2")
+        depends_on("xz libs=shared", when="+lzma")
+        depends_on("expat", when="+pyexpat")
+        depends_on("libffi", when="+ctypes")
+        # https://docs.python.org/3/whatsnew/3.11.html#build-changes
+        depends_on("tk@8.5.12:", when="@3.11: +tkinter")
+        depends_on("tk", when="+tkinter")
+        depends_on("tcl@8.5.12:", when="@3.11: +tkinter")
+        depends_on("tcl", when="+tkinter")
+        depends_on("uuid", when="+uuid")
+        depends_on("tix", when="+tix")
+        depends_on("libxcrypt", when="+crypt")
+
+    # Python needs to be patched to build extensions w/ mixed C/C++ code:
+    # https://github.com/NixOS/nixpkgs/pull/19585/files
+    # https://bugs.python.org/issue1222585
+    #
+    # NOTE: This patch puts Spack's default Python installation out of
+    # sync with standard Python installs. If you're using such an
+    # installation as an external and encountering build issues with mixed
+    # C/C++ modules, consider installing a Spack-managed Python with
+    # this patch instead. For more information, see:
+    # https://github.com/spack/spack/pull/16856
+    patch("python-3.7.2-distutils-C++.patch", when="@3.7.2")
+    patch("python-3.7.3-distutils-C++.patch", when="@3.7.3")
+    patch("python-3.7.4+-distutils-C++.patch", when="@3.7.4:3.10")
+    patch("python-3.7.4+-distutils-C++-testsuite.patch", when="@3.7.4:3.11")
+    patch("python-3.11-distutils-C++.patch", when="@3.11.0:3.11")
+    patch("cpython-windows-externals.patch", when="@:3.9.6 platform=windows")
+    patch("tkinter-3.7.patch", when="@3.7 platform=darwin")
+    # Patch the setup script to deny that tcl/x11 exists rather than allowing
+    # autodetection of (possibly broken) system components
+    patch("tkinter-3.8.patch", when="@3.8:3.9 ~tkinter")
+    patch("tkinter-3.10.patch", when="@3.10.0:3.10 ~tkinter")
+    patch("tkinter-3.11.patch", when="@3.11.0:3.11 ~tkinter")
+
+    # Ensure that distutils chooses correct compiler option for RPATH:
+    patch("rpath-non-gcc.patch", when="@:3.11")
+
+    # Ensure that distutils chooses correct compiler option for RPATH on fj:
+    patch("fj-rpath-3.1.patch", when="@:3.9.7,3.10.0 %fj")
+    patch("fj-rpath-3.9.patch", when="@3.9.8:3.9,3.10.1:3.11 %fj")
+
+    # Fixes build with the Intel compilers
+    # https://github.com/python/cpython/pull/16717
+    patch("intel-3.7.patch", when="@3.7.1:3.7.5 %intel")
+
+    # CPython tries to build an Objective-C file with GCC's C frontend
+    # https://github.com/spack/spack/pull/16222
+    # https://github.com/python/cpython/pull/13306
+    conflicts(
+        "%gcc platform=darwin",
+        msg="CPython does not compile with GCC on macOS yet, use clang. "
+        "See: https://github.com/python/cpython/pull/13306",
+    )
+    conflicts("%nvhpc")
+
+    # https://bugs.python.org/issue45405
+    conflicts("@:3.7.12,3.8.0:3.8.12,3.9.0:3.9.7,3.10.0", when="%apple-clang@13:")
+
+    # See https://github.com/python/cpython/issues/106424
+    # datetime.now(timezone.utc) segfaults
+    conflicts("@3.9:", when="%oneapi@2022.2.1:2023")
+
+    # Used to cache various attributes that are expensive to compute
+    _config_vars: Dict[str, Dict[str, str]] = {}
+
+    # An in-source build with --enable-optimizations fails for python@3.X
+    build_directory = "spack-build"
+
+    executables = [r"^python\d?$"]
+
+    @classmethod
+    def determine_version(cls, exe):
+        # Newer versions of Python support `--version`,
+        # but older versions only support `-V`
+        # Output looks like:
+        #   Python 3.7.7
+        # On pre-production Ubuntu, this is also possible:
+        #   Python 3.10.2+
+        output = Executable(exe)("-V", output=str, error=str)
+        match = re.search(r"Python\s+([A-Za-z0-9_.-]+)", output)
+        return match.group(1) if match else None
+
+    @classmethod
+    def determine_variants(cls, exes, version_str):
+        python = Executable(exes[0])
+
+        variants = ""
+        for exe in exes:
+            if os.path.basename(exe) == "python":
+                variants += "+pythoncmd"
+                break
+        else:
+            variants += "~pythoncmd"
+
+        for module in [
+            "readline",
+            "sqlite3",
+            "dbm",
+            "nis",
+            "zlib",
+            "bz2",
+            "lzma",
+            "ctypes",
+            "tkinter",
+            "uuid",
+        ]:
+            try:
+                python("-c", "import " + module, error=os.devnull)
+                variants += "+" + module
+            except ProcessError:
+                variants += "~" + module
+
+        # Some variants enable multiple modules
+        try:
+            python("-c", "import ssl", error=os.devnull)
+            python("-c", "import hashlib", error=os.devnull)
+            variants += "+ssl"
+        except ProcessError:
+            variants += "~ssl"
+
+        try:
+            python("-c", "import xml.parsers.expat", error=os.devnull)
+            python("-c", "import xml.etree.ElementTree", error=os.devnull)
+            variants += "+pyexpat"
+        except ProcessError:
+            variants += "~pyexpat"
+
+        # Some variant names do not match module names
+        if "+tkinter" in variants:
+            try:
+                python("-c", "import tkinter.tix", error=os.devnull)
+                variants += "+tix"
+            except ProcessError:
+                variants += "~tix"
+
+        # Some modules are platform-dependent
+        if sys.platform != "win32":
+            try:
+                python("-c", "import crypt", error=os.devnull)
+                variants += "+crypt"
+            except ProcessError:
+                variants += "~crypt"
+
+        return variants
+
+    def url_for_version(self, version):
+        url = "https://www.python.org/ftp/python/{0}/Python-{1}.tgz"
+        return url.format(re.split("[a-z]", str(version))[0], version)
+
+    def patch(self):
+        # NOTE: Python's default installation procedure makes it possible for a
+        # user's local configurations to change the Spack installation.  In
+        # order to prevent this behavior for a full installation, we must
+        # modify the installation script so that it ignores user files.
+        ff = FileFilter("Makefile.pre.in")
+        ff.filter(
+            r"^(.*)setup\.py(.*)((build)|(install))(.*)$", r"\1setup.py\2 --no-user-cfg \3\6"
+        )
+
+    def setup_build_environment(self, env):
+        spec = self.spec
+
+        # TODO: Python has incomplete support for Python modules with mixed
+        # C/C++ source, and patches are required to enable building for these
+        # modules. All Python versions without a viable patch are installed
+        # with a warning message about this potentially erroneous behavior.
+        if not spec.satisfies("@3.7.2:"):
+            tty.warn(
+                (
+                    'Python v{0} does not have the C++ "distutils" patch; '
+                    "errors may occur when installing Python modules w/ "
+                    "mixed C/C++ source files."
+                ).format(self.version)
+            )
+
+        env.unset("PYTHONPATH")
+        env.unset("PYTHONHOME")
+
+        # avoid build error on fugaku
+        if spec.satisfies("@3.10.0 arch=linux-rhel8-a64fx"):
+            if spec.satisfies("%gcc") or spec.satisfies("%fj"):
+                env.unset("LC_ALL")
+
+        # https://github.com/python/cpython/issues/87275
+        if spec.satisfies("@:3.9.5 +optimizations %apple-clang"):
+            xcrun = Executable("/usr/bin/xcrun")
+            env.set("LLVM_AR", xcrun("-find", "ar", output=str).strip())
+
+    def flag_handler(self, name, flags):
+        # python 3.8 requires -fwrapv when compiled with intel
+        if self.spec.satisfies("@3.8: %intel"):
+            if name == "cflags":
+                flags.append("-fwrapv")
+
+        # Fix for following issues for python with aocc%3.2.0:
+        # https://github.com/spack/spack/issues/29115
+        # https://github.com/spack/spack/pull/28708
+        if self.spec.satisfies("%aocc@3.2.0"):
+            if name == "cflags":
+                flags.extend(["-mllvm", "-disable-indvar-simplify=true"])
+
+        # allow flags to be passed through compiler wrapper
+        return (flags, None, None)
+
+    @property
+    def plat_arch(self):
+        """
+        String referencing platform architecture
+        filtered through Python's Windows build file
+        architecture support map
+
+        Note: This function really only makes
+        sense to use on Windows, could be overridden to
+        cross compile however.
+        """
+
+        arch_map = {"AMD64": "x64", "x86": "Win32", "IA64": "Win32", "EM64T": "Win32"}
+        arch = platform.machine()
+        if arch in arch_map:
+            arch = arch_map[arch]
+        return arch
+
+    @property
+    def win_build_params(self):
+        """
+        Arguments must be passed to the Python build batch script
+        in order to configure it to spec and system.
+        A number of these toggle optional MSBuild Projects
+        directly corresponding to the python support of the same
+        name.
+        """
+        args = []
+        args.append("-p %s" % self.plat_arch)
+        if self.spec.satisfies("+debug"):
+            args.append("-d")
+        if self.spec.satisfies("~ctypes"):
+            args.append("--no-ctypes")
+        if self.spec.satisfies("~ssl"):
+            args.append("--no-ssl")
+        if self.spec.satisfies("~tkinter"):
+            args.append("--no-tkinter")
+        return args
+
+    def win_installer(self, prefix):
+        """
+        Python on Windows does not export an install target
+        so we must handcraft one here. This structure
+        directly mimics the install tree of the Python
+        Installer on Windows.
+
+        Parameters:
+            prefix (str): Install prefix for package
+        """
+        proj_root = self.stage.source_path
+        pcbuild_root = os.path.join(proj_root, "PCbuild")
+        build_root = os.path.join(pcbuild_root, platform.machine().lower())
+        include_dir = os.path.join(proj_root, "Include")
+        copy_tree(include_dir, prefix.include)
+        doc_dir = os.path.join(proj_root, "Doc")
+        copy_tree(doc_dir, prefix.Doc)
+        tools_dir = os.path.join(proj_root, "Tools")
+        copy_tree(tools_dir, prefix.Tools)
+        lib_dir = os.path.join(proj_root, "Lib")
+        copy_tree(lib_dir, prefix.Lib)
+        pyconfig = os.path.join(proj_root, "PC", "pyconfig.h")
+        copy(pyconfig, prefix.include)
+        shared_libraries = []
+        shared_libraries.extend(glob.glob("%s\\*.exe" % build_root))
+        shared_libraries.extend(glob.glob("%s\\*.dll" % build_root))
+        shared_libraries.extend(glob.glob("%s\\*.pyd" % build_root))
+        os.makedirs(prefix.DLLs)
+        for lib in shared_libraries:
+            file_name = os.path.basename(lib)
+            if (
+                file_name.endswith(".exe")
+                or (file_name.endswith(".dll") and "python" in file_name)
+                or "vcruntime" in file_name
+            ):
+                copy(lib, prefix)
+            else:
+                copy(lib, prefix.DLLs)
+        static_libraries = glob.glob("%s\\*.lib" % build_root)
+        os.makedirs(prefix.libs, exist_ok=True)
+        for lib in static_libraries:
+            copy(lib, prefix.libs)
+
+    def configure_args(self):
+        spec = self.spec
+        config_args = []
+        cflags = []
+
+        # setup.py needs to be able to read the CPPFLAGS and LDFLAGS
+        # as it scans for the library and headers to build
+        link_deps = spec.dependencies(deptype="link")
+
+        if link_deps:
+            # Header files are often included assuming they reside in a
+            # subdirectory of prefix.include, e.g. #include <openssl/ssl.h>,
+            # which is why we don't use HeaderList here. The header files of
+            # libffi reside in prefix.lib but the configure script of Python
+            # finds them using pkg-config.
+            cppflags = " ".join("-I" + spec[dep.name].prefix.include for dep in link_deps)
+
+            # Currently, the only way to get SpecBuildInterface wrappers of the
+            # dependencies (which we need to get their 'libs') is to get them
+            # using spec.__getitem__.
+            ldflags = " ".join(spec[dep.name].libs.search_flags for dep in link_deps)
+
+            config_args.extend(["CPPFLAGS=" + cppflags, "LDFLAGS=" + ldflags])
+
+        if "+optimizations" in spec:
+            config_args.append("--enable-optimizations")
+            # Prefer thin LTO for faster compilation times.
+            if "@3.11.0: %clang@3.9:" in spec or "@3.11.0: %apple-clang@8:" in spec:
+                config_args.append("--with-lto=thin")
+            else:
+                config_args.append("--with-lto")
+            config_args.append("--with-computed-gotos")
+
+        if spec.satisfies("@3.7 %intel"):
+            config_args.append("--with-icc={0}".format(spack_cc))
+
+        if "+debug" in spec:
+            config_args.append("--with-pydebug")
+        else:
+            config_args.append("--without-pydebug")
+
+        if "+shared" in spec:
+            config_args.append("--enable-shared")
+        else:
+            config_args.append("--disable-shared")
+
+        config_args.append("--without-ensurepip")
+
+        if "+pic" in spec:
+            cflags.append(self.compiler.cc_pic_flag)
+
+        if "+ssl" in spec:
+            config_args.append("--with-openssl={0}".format(spec["openssl"].prefix))
+
+        if "+dbm" in spec:
+            # Default order is ndbm:gdbm:bdb
+            config_args.append("--with-dbmliborder=gdbm")
+        else:
+            config_args.append("--with-dbmliborder=")
+
+        if "+pyexpat" in spec:
+            config_args.append("--with-system-expat")
+        else:
+            config_args.append("--without-system-expat")
+
+        if self.version < Version("3.12.0"):
+            if "+ctypes" in spec:
+                config_args.append("--with-system-ffi")
+            else:
+                config_args.append("--without-system-ffi")
+
+        if "+tkinter" in spec:
+            config_args.extend(
+                [
+                    "--with-tcltk-includes=-I{0} -I{1}".format(
+                        spec["tcl"].prefix.include, spec["tk"].prefix.include
+                    ),
+                    "--with-tcltk-libs={0} {1}".format(
+                        spec["tcl"].libs.ld_flags, spec["tk"].libs.ld_flags
+                    ),
+                ]
+            )
+
+        # https://docs.python.org/3.8/library/sqlite3.html#f1
+        if spec.satisfies("+sqlite3 ^sqlite+dynamic_extensions"):
+            config_args.append("--enable-loadable-sqlite-extensions")
+
+        if spec.satisfies("%oneapi"):
+            cflags.append("-fp-model=strict")
+
+        if cflags:
+            config_args.append("CFLAGS={0}".format(" ".join(cflags)))
+
+        if self.version >= Version("3.12.0") and sys.platform == "darwin":
+            config_args.append("CURSES_LIBS={0}".format(spec["ncurses"].libs.link_flags))
+
+        return config_args
+
+    def configure(self, spec, prefix):
+        """Runs configure with the arguments specified in
+        :meth:`~spack.build_systems.autotools.AutotoolsPackage.configure_args`
+        and an appropriately set prefix.
+        """
+        with working_dir(self.stage.source_path, create=True):
+            if sys.platform == "win32":
+                pass
+            else:
+                options = getattr(self, "configure_flag_args", [])
+                options += ["--prefix={0}".format(prefix)]
+                options += self.configure_args()
+                configure(*options)
+
+    def build(self, spec, prefix):
+        """Makes the build targets specified by
+        :py:attr:``~.AutotoolsPackage.build_targets``
+        """
+        # Windows builds use a batch script to drive
+        # configure and build in one step
+        with working_dir(self.stage.source_path):
+            if sys.platform == "win32":
+                pcbuild_root = os.path.join(self.stage.source_path, "PCbuild")
+                builder_cmd = os.path.join(pcbuild_root, "build.bat")
+                try:
+                    subprocess.check_output(  # novermin
+                        " ".join([builder_cmd] + self.win_build_params), stderr=subprocess.STDOUT
+                    )
+                except subprocess.CalledProcessError as e:
+                    raise ProcessError(
+                        "Process exited with status %d" % e.returncode,
+                        long_message=e.output.decode("utf-8"),
+                    )
+            else:
+                # See https://autotools.io/automake/silent.html
+                params = ["V=1"]
+                params += self.build_targets
+                make(*params)
+
+    def install(self, spec, prefix):
+        """Makes the install targets specified by
+        :py:attr:``~.AutotoolsPackage.install_targets``
+        """
+        with working_dir(self.stage.source_path):
+            if sys.platform == "win32":
+                self.win_installer(prefix)
+            else:
+                # See https://github.com/python/cpython/issues/102007
+                make(*self.install_targets, parallel=False)
+
+    @run_after("install")
+    def filter_compilers(self):
+        """Run after install to tell the configuration files and Makefiles
+        to use the compilers that Spack built the package with.
+
+        If this isn't done, they'll have CC and CXX set to Spack's generic
+        cc and c++. We want them to be bound to whatever compiler
+        they were built with."""
+        if sys.platform == "win32":
+            return
+        kwargs = {"ignore_absent": True, "backup": False, "string": True}
+
+        filenames = [self.get_sysconfigdata_name(), self.config_vars["makefile_filename"]]
+
+        filter_file(spack_cc, self.compiler.cc, *filenames, **kwargs)
+        if spack_cxx and self.compiler.cxx:
+            filter_file(spack_cxx, self.compiler.cxx, *filenames, **kwargs)
+
+    @run_after("install")
+    def symlink(self):
+        if sys.platform == "win32":
+            return
+        spec = self.spec
+        prefix = self.prefix
+
+        if spec.satisfies("+pythoncmd"):
+            os.symlink(os.path.join(prefix.bin, "python3"), os.path.join(prefix.bin, "python"))
+            os.symlink(
+                os.path.join(prefix.bin, "python3-config"),
+                os.path.join(prefix.bin, "python-config"),
+            )
+
+    @run_after("install")
+    def install_python_gdb(self):
+        # https://devguide.python.org/gdb/
+        src = os.path.join("Tools", "gdb", "libpython.py")
+        if os.path.exists(src):
+            install(src, self.command.path + "-gdb.py")
+
+    @run_after("install")
+    @on_package_attributes(run_tests=True)
+    def import_tests(self):
+        """Test that basic Python functionality works."""
+
+        spec = self.spec
+
+        with working_dir("spack-test", create=True):
+            # Ensure that readline module works
+            if "+readline" in spec:
+                self.command("-c", "import readline")
+
+            # Ensure that ssl module works
+            if "+ssl" in spec:
+                self.command("-c", "import ssl")
+                self.command("-c", "import hashlib")
+
+            # Ensure that sqlite3 module works
+            if "+sqlite3" in spec:
+                self.command("-c", "import sqlite3")
+
+            # Ensure that dbm module works
+            if "+dbm" in spec:
+                self.command("-c", "import dbm")
+
+            # Ensure that nis module works
+            if "+nis" in spec:
+                self.command("-c", "import nis")
+
+            # Ensure that zlib module works
+            if "+zlib" in spec:
+                self.command("-c", "import zlib")
+
+            # Ensure that bz2 module works
+            if "+bz2" in spec:
+                self.command("-c", "import bz2")
+
+            # Ensure that lzma module works
+            if "+lzma" in spec:
+                self.command("-c", "import lzma")
+
+            # Ensure that pyexpat module works
+            if "+pyexpat" in spec:
+                self.command("-c", "import xml.parsers.expat")
+                self.command("-c", "import xml.etree.ElementTree")
+
+            # Ensure that ctypes module works
+            if "+ctypes" in spec:
+                self.command("-c", "import ctypes")
+
+            # Ensure that tkinter module works
+            # https://wiki.python.org/moin/TkInter
+            if "+tkinter" in spec:
+                # Only works if ForwardX11Trusted is enabled, i.e. `ssh -Y`
+                if "DISPLAY" in env:
+                    self.command("-c", "import tkinter; tkinter._test()")
+                else:
+                    self.command("-c", "import tkinter")
+
+            # Ensure that uuid module works
+            if "+uuid" in spec:
+                self.command("-c", "import uuid")
+
+            # Ensure that tix module works
+            if "+tix" in spec:
+                self.command("-c", "import tkinter.tix")
+
+            # Ensure that crypt module works
+            if "+crypt" in spec:
+                self.command("-c", "import crypt")
+
+    # ========================================================================
+    # Set up environment to make install easy for python extensions.
+    # ========================================================================
+
+    @property
+    def command(self):
+        """Returns the Python command, which may vary depending
+        on the version of Python and how it was installed.
+
+        In general, Python 3 only comes with a ``python3`` command. However, some
+        package managers will symlink ``python`` to ``python3``, while others
+        may contain ``python3.11``, ``python3.10``, and ``python3.9`` in the
+        same directory.
+
+        Returns:
+            Executable: the Python command
+        """
+        # We need to be careful here. If the user is using an externally
+        # installed python, several different commands could be located
+        # in the same directory. Be as specific as possible. Search for:
+        #
+        # * python3.11
+        # * python3
+        # * python
+        #
+        # in that order if using python@3.11.0, for example.
+        suffixes = [self.spec.version.up_to(2), self.spec.version.up_to(1), ""]
+        file_extension = "" if sys.platform != "win32" else ".exe"
+        patterns = [f"python{ver}{file_extension}" for ver in suffixes]
+        root = self.prefix.bin if sys.platform != "win32" else self.prefix
+        path = find_first(root, files=patterns)
+
+        if path is not None:
+            return Executable(path)
+
+        else:
+            # Give a last try at rhel8 platform python
+            if self.spec.external and self.prefix == "/usr" and self.spec.satisfies("os=rhel8"):
+                path = os.path.join(self.prefix, "libexec", "platform-python")
+                if os.path.exists(path):
+                    return Executable(path)
+
+        raise RuntimeError(
+            f"cannot to locate the '{self.name}' command in {root} or its subdirectories"
+        )
+
+    @property
+    def config_vars(self):
+        """Return a set of variable definitions associated with a Python installation.
+
+        Wrapper around various ``sysconfig`` functions. To see these variables on the
+        command line, run:
+
+        .. code-block:: console
+
+           $ python -m sysconfig
+
+        Returns:
+            dict: variable definitions
+        """
+        cmd = """
+import json
+from sysconfig import (
+    get_config_vars,
+    get_config_h_filename,
+    get_makefile_filename,
+    get_paths,
+)
+
+config = get_config_vars()
+config['config_h_filename'] = get_config_h_filename()
+config['makefile_filename'] = get_makefile_filename()
+config.update(get_paths())
+
+print(json.dumps(config))
+"""
+
+        dag_hash = self.spec.dag_hash()
+        lib_prefix = "lib" if sys.platform != "win32" else ""
+        if dag_hash not in self._config_vars:
+            # Default config vars
+            version = self.version.up_to(2)
+            if sys.platform == "win32":
+                version = str(version).split(".")[0]
+            config = {
+                # get_config_vars
+                "BINDIR": self.prefix.bin,
+                "CC": "cc",
+                "CONFINCLUDEPY": self.prefix.include.join("python{}").format(version),
+                "CXX": "c++",
+                "INCLUDEPY": self.prefix.include.join("python{}").format(version),
+                "LIBDEST": self.prefix.lib.join("python{}").format(version),
+                "LIBDIR": self.prefix.lib,
+                "LIBPL": self.prefix.lib.join("python{0}")
+                .join("config-{0}-{1}")
+                .format(version, sys.platform),
+                "LDLIBRARY": "{}python{}.{}".format(lib_prefix, version, dso_suffix),
+                "LIBRARY": "{}python{}.{}".format(lib_prefix, version, stat_suffix),
+                "LDSHARED": "cc",
+                "LDCXXSHARED": "c++",
+                "PYTHONFRAMEWORKPREFIX": "/System/Library/Frameworks",
+                "base": self.prefix,
+                "installed_base": self.prefix,
+                "installed_platbase": self.prefix,
+                "platbase": self.prefix,
+                "prefix": self.prefix,
+                # get_config_h_filename
+                "config_h_filename": self.prefix.include.join("python{}")
+                .join("pyconfig.h")
+                .format(version),
+                # get_makefile_filename
+                "makefile_filename": self.prefix.lib.join("python{0}")
+                .join("config-{0}-{1}")
+                .Makefile.format(version, sys.platform),
+                # get_paths
+                "data": self.prefix,
+                "include": self.prefix.include.join("python{}".format(version)),
+                "platinclude": self.prefix.include64.join("python{}".format(version)),
+                "platlib": self.prefix.lib64.join("python{}".format(version)).join(
+                    "site-packages"
+                ),
+                "platstdlib": self.prefix.lib64.join("python{}".format(version)),
+                "purelib": self.prefix.lib.join("python{}".format(version)).join("site-packages"),
+                "scripts": self.prefix.bin,
+                "stdlib": self.prefix.lib.join("python{}".format(version)),
+            }
+
+            try:
+                config.update(json.loads(self.command("-c", cmd, output=str)))
+            except (ProcessError, RuntimeError):
+                pass
+            self._config_vars[dag_hash] = config
+        return self._config_vars[dag_hash]
+
+    def get_sysconfigdata_name(self):
+        """Return the full path name of the sysconfigdata file."""
+
+        libdest = self.config_vars["LIBDEST"]
+
+        cmd = "from sysconfig import _get_sysconfigdata_name; "
+        cmd += "print(_get_sysconfigdata_name())"
+        filename = self.command("-c", cmd, output=str).strip()
+        filename += ".py"
+
+        return join_path(libdest, filename)
+
+    @property
+    def home(self):
+        """Most of the time, ``PYTHONHOME`` is simply
+        ``spec['python'].prefix``. However, if the user is using an
+        externally installed python, it may be symlinked. For example,
+        Homebrew installs python in ``/usr/local/Cellar/python/2.7.12_2``
+        and symlinks it to ``/usr/local``. Users may not know the actual
+        installation directory and add ``/usr/local`` to their
+        ``packages.yaml`` unknowingly. Query the python executable to
+        determine exactly where it is installed.
+        """
+        return Prefix(self.config_vars["base"])
+
+    def find_library(self, library):
+        # Spack installs libraries into lib, except on openSUSE where it installs them
+        # into lib64. If the user is using an externally installed package, it may be
+        # in either lib or lib64, so we need to ask Python where its LIBDIR is.
+        libdir = self.config_vars["LIBDIR"]
+
+        # Debian and derivatives use a triplet subdir under /usr/lib, LIBPL can be used
+        # to get the Python library directory
+        libpldir = self.config_vars["LIBPL"]
+
+        # The system Python installation on macOS and Homebrew installations
+        # install libraries into a Frameworks directory
+        frameworkprefix = self.config_vars["PYTHONFRAMEWORKPREFIX"]
+
+        # Get the active Xcode environment's Framework location.
+        macos_developerdir = os.environ.get("DEVELOPER_DIR")
+        if macos_developerdir and os.path.exists(macos_developerdir):
+            macos_developerdir = os.path.join(macos_developerdir, "Library", "Frameworks")
+        else:
+            macos_developerdir = ""
+
+        # Windows libraries are installed directly to BINDIR
+        win_bin_dir = self.config_vars["BINDIR"]
+        win_root_dir = self.config_vars["prefix"]
+
+        directories = [
+            libdir,
+            libpldir,
+            frameworkprefix,
+            macos_developerdir,
+            win_bin_dir,
+            win_root_dir,
+        ]
+
+        if self.spec.satisfies("platform=windows"):
+            lib_dirs = ["libs"]
+        else:
+            # The Python shipped with Xcode command line tools isn't in any of these locations
+            lib_dirs = ["lib", "lib64"]
+
+        for subdir in lib_dirs:
+            directories.append(os.path.join(self.config_vars["base"], subdir))
+
+        directories = dedupe(directories)
+        for directory in directories:
+            path = os.path.join(directory, library)
+            if os.path.exists(path):
+                return LibraryList(path)
+
+    @property
+    def libs(self):
+        py_version = self.version.up_to(2)
+        if sys.platform == "win32":
+            py_version = str(py_version).replace(".", "")
+        lib_prefix = "lib" if sys.platform != "win32" else ""
+        # The values of LDLIBRARY and LIBRARY aren't reliable. Intel Python uses a
+        # static binary but installs shared libraries, so sysconfig reports
+        # libpythonX.Y.a but only libpythonX.Y.so exists. So we add our own paths, too.
+
+        # With framework python on macOS, self.config_vars["LDLIBRARY"] can point
+        # to a library that is not linkable because it does not have the required
+        # suffix of a shared library (it is called "Python" without extention).
+        # The linker then falls back to libPython.tbd in the default macOS
+        # software tree, which security settings prohibit to link against
+        # (your binary is not an allowed client of /path/to/libPython.tbd).
+        # To avoid this, we replace the entry in config_vars with a default value.
+        file_extension_shared = os.path.splitext(self.config_vars["LDLIBRARY"])[-1]
+        if file_extension_shared == "":
+            shared_libs = []
+        else:
+            shared_libs = [self.config_vars["LDLIBRARY"]]
+        shared_libs += ["{}python{}.{}".format(lib_prefix, py_version, dso_suffix)]
+        # Like LDLIBRARY for Python on Mac OS, LIBRARY may refer to an un-linkable object
+        file_extension_static = os.path.splitext(self.config_vars["LIBRARY"])[-1]
+        if file_extension_static == "":
+            static_libs = []
+        else:
+            static_libs = [self.config_vars["LIBRARY"]]
+        static_libs += ["{}python{}.{}".format(lib_prefix, py_version, stat_suffix)]
+
+        # The +shared variant isn't reliable, as `spack external find` currently can't
+        # detect it. If +shared, prefer the shared libraries, but check for static if
+        # those aren't found. Vice versa for ~shared.
+        if self.spec.satisfies("platform=windows"):
+            # Since we are searching for link libraries, on Windows search only for
+            # ".Lib" extensions by default as those represent import libraries for implict links.
+            candidates = static_libs
+        elif self.spec.satisfies("+shared"):
+            candidates = shared_libs + static_libs
+        else:
+            candidates = static_libs + shared_libs
+
+        for candidate in dedupe(candidates):
+            lib = self.find_library(candidate)
+            if lib:
+                return lib
+
+        raise spack.error.NoLibrariesError(
+            "Unable to find {} libraries with the following names:\n\n* ".format(self.name)
+            + "\n* ".join(candidates)
+        )
+
+    @property
+    def headers(self):
+        # Locations where pyconfig.h could be
+        # This varies by system, especially on macOS where the command line tools are
+        # installed in a very different directory from the system python interpreter.
+        py_version = str(self.version.up_to(2))
+        candidates = [
+            os.path.dirname(self.config_vars["config_h_filename"]),
+            self.config_vars["INCLUDEPY"],
+            self.config_vars["CONFINCLUDEPY"],
+            os.path.join(self.config_vars["base"], "include", py_version),
+            os.path.join(self.config_vars["base"], "Headers"),
+        ]
+        candidates = list(dedupe(candidates))
+
+        for directory in candidates:
+            headers = find_headers("pyconfig", directory)
+            if headers:
+                config_h = headers[0]
+                break
+        else:
+            raise spack.error.NoHeadersError(
+                "Unable to locate {} headers in any of these locations:\n\n* ".format(self.name)
+                + "\n* ".join(candidates)
+            )
+
+        headers.directories = [os.path.dirname(config_h)]
+        return headers
+
+    # https://docs.python.org/3/library/sysconfig.html#installation-paths
+    # https://discuss.python.org/t/understanding-site-packages-directories/12959
+    # https://github.com/pypa/pip/blob/22.1/src/pip/_internal/locations/__init__.py
+    # https://github.com/pypa/installer/pull/103
+
+    # NOTE: XCode Python's sysconfing module was incorrectly patched, and hard-codes
+    # everything to be installed in /Library/Python. Therefore, we need to use a
+    # fallback in the following methods. For more information, see:
+    # https://github.com/pypa/pip/blob/22.1/src/pip/_internal/locations/__init__.py#L486
+
+    @property
+    def platlib(self):
+        """Directory for site-specific, platform-specific files.
+
+        Exact directory depends on platform/OS/Python version. Examples include:
+
+        * ``lib/pythonX.Y/site-packages`` on most POSIX systems
+        * ``lib64/pythonX.Y/site-packages`` on RHEL/CentOS/Fedora with system Python
+        * ``lib/pythonX/dist-packages`` on Debian/Ubuntu with system Python
+        * ``lib/python/site-packages`` on macOS with framework Python
+        * ``Lib/site-packages`` on Windows
+
+        Returns:
+            str: platform-specific site-packages directory
+        """
+        prefix = self.config_vars["platbase"] + os.sep
+        path = self.config_vars["platlib"]
+        if path.startswith(prefix):
+            return path.replace(prefix, "")
+        return os.path.join("lib64", f"python{self.version.up_to(2)}", "site-packages")
+
+    @property
+    def purelib(self):
+        """Directory for site-specific, non-platform-specific files.
+
+        Exact directory depends on platform/OS/Python version. Examples include:
+
+        * ``lib/pythonX.Y/site-packages`` on most POSIX systems
+        * ``lib/pythonX/dist-packages`` on Debian/Ubuntu with system Python
+        * ``lib/python/site-packages`` on macOS with framework Python
+        * ``Lib/site-packages`` on Windows
+
+        Returns:
+            str: platform-independent site-packages directory
+        """
+        prefix = self.config_vars["base"] + os.sep
+        path = self.config_vars["purelib"]
+        if path.startswith(prefix):
+            return path.replace(prefix, "")
+        return os.path.join("lib", f"python{self.version.up_to(2)}", "site-packages")
+
+    @property
+    def include(self):
+        """Directory for non-platform-specific header files.
+
+        Exact directory depends on platform/Python version/ABI flags. Examples include:
+
+        * ``include/pythonX.Y`` on most POSIX systems
+        * ``include/pythonX.Yd`` for debug builds
+        * ``include/pythonX.Ym`` for malloc builds
+        * ``include/pythonX.Yu`` for wide unicode builds
+        * ``include`` on macOS with framework Python
+        * ``Include`` on Windows
+
+        Returns:
+            str: platform-independent header file directory
+        """
+        prefix = self.config_vars["installed_base"] + os.sep
+        path = self.config_vars["include"]
+        if path.startswith(prefix):
+            return path.replace(prefix, "")
+        return os.path.join("include", "python{}".format(self.version.up_to(2)))
+
+    def setup_dependent_build_environment(self, env, dependent_spec):
+        """Set PYTHONPATH to include the site-packages directory for the
+        extension and any other python extensions it depends on.
+        """
+        # We need to make sure that the extensions are compiled and linked with
+        # the Spack wrapper. Paths to the executables that are used for these
+        # operations are normally taken from the sysconfigdata file, which we
+        # modify after the installation (see method filter compilers). The
+        # modified file contains paths to the real compilers, not the wrappers.
+        # The values in the file, however, can be overridden with environment
+        # variables. The first variable, CC (CXX), which is used for
+        # compilation, is set by Spack for the dependent package by default.
+        # That is not 100% correct because the value for CC (CXX) in the
+        # sysconfigdata file often contains additional compiler flags (e.g.
+        # -pthread), which we lose by simply setting CC (CXX) to the path to the
+        # Spack wrapper. Moreover, the user might try to build an extension with
+        # a compiler that is different from the one that was used to build
+        # Python itself, which might have unexpected side effects. However, the
+        # experience shows that none of the above is a real issue and we will
+        # not try to change the default behaviour. Given that, we will simply
+        # try to modify LDSHARED (LDCXXSHARED), the second variable, which is
+        # used for linking, in a consistent manner.
+
+        for compile_var, link_var in [("CC", "LDSHARED"), ("CXX", "LDCXXSHARED")]:
+            # First, we get the values from the sysconfigdata:
+            config_compile = self.config_vars[compile_var]
+            config_link = self.config_vars[link_var]
+
+            # The dependent environment will have the compilation command set to
+            # the following:
+            new_compile = join_path(
+                spack.paths.build_env_path,
+                dependent_spec.package.compiler.link_paths[compile_var.lower()],
+            )
+
+            # Normally, the link command starts with the compilation command:
+            if config_link.startswith(config_compile):
+                new_link = new_compile + config_link[len(config_compile) :]
+            else:
+                # Otherwise, we try to replace the compiler command if it
+                # appears "in the middle" of the link command; to avoid
+                # mistaking some substring of a path for the compiler (e.g. to
+                # avoid replacing "gcc" in "-L/path/to/gcc/"), we require that
+                # the compiler command be surrounded by spaces. Note this may
+                # leave "config_link" unchanged if the compilation command does
+                # not appear in the link command at all, for example if "ld" is
+                # invoked directly (no change would be required in that case
+                # because Spack arranges for the Spack ld wrapper to be the
+                # first instance of "ld" in PATH).
+                new_link = config_link.replace(f" {config_compile} ", f" {new_compile} ")
+
+            # There is logic in the sysconfig module that is sensitive to the
+            # fact that LDSHARED is set in the environment, therefore we export
+            # the variable only if the new value is different from what we got
+            # from the sysconfigdata file:
+            if config_link != new_link and sys.platform != "win32":
+                env.set(link_var, new_link)
+
+    def setup_dependent_run_environment(self, env, dependent_spec):
+        """Set PYTHONPATH to include the site-packages directory for the
+        extension and any other python extensions it depends on.
+        """
+        if not dependent_spec.package.extends(self.spec) or dependent_spec.dependencies(
+            "python-venv"
+        ):
+            return
+
+        # Packages may be installed in platform-specific or platform-independent site-packages
+        # directories
+        for directory in {self.platlib, self.purelib}:
+            env.prepend_path("PYTHONPATH", os.path.join(dependent_spec.prefix, directory))
+
+    def setup_dependent_package(self, module, dependent_spec):
+        """Called before python modules' install() methods."""
+        module.python = self.command
+        module.python_include = join_path(dependent_spec.prefix, self.include)
+        module.python_platlib = join_path(dependent_spec.prefix, self.platlib)
+        module.python_purelib = join_path(dependent_spec.prefix, self.purelib)
+
+    def add_files_to_view(self, view, merge_map, skip_if_exists=True):
+        """Make the view a virtual environment if it isn't one already.
+
+        If `python-venv` is linked into the view, it will already be a virtual
+        environment. If not, then this is an older python that doesn't use the
+        python-venv support, or we may be using python packages that
+        use ``depends_on("python")`` but not ``extends("python")``.
+
+        We used to copy the python interpreter in, but we can get the same effect in a
+        simpler way by adding a ``pyvenv.cfg`` to the environment.
+
+        """
+        super().add_files_to_view(view, merge_map, skip_if_exists=skip_if_exists)
+
+        # location of python inside the view, where we will put the venv config
+        projection = view.get_projection_for_spec(self.spec)
+        pyvenv_cfg = os.path.join(projection, "pyvenv.cfg")
+        if os.path.lexists(pyvenv_cfg):
+            return
+
+        # don't put a pyvenv.cfg in a copy view
+        if view.link_type == "copy":
+            return
+
+        with open(pyvenv_cfg, "w") as cfg_file:
+            cfg_file.write(make_pyvenv_cfg(self.spec["python"], projection))
+
+    def test_hello_world(self):
+        """run simple hello world program"""
+        # do not use self.command because we are also testing the run env
+        python = self.spec["python"].command
+
+        msg = "hello world!"
+        out = python("-c", f'print("{msg}")', output=str.split, error=str.split)
+        assert msg in out
+
+    def test_import_executable(self):
+        """ensure import of installed executable works"""
+        python = self.spec["python"].command
+
+        out = python("-c", "import sys; print(sys.executable)", output=str.split, error=str.split)
+        assert self.spec.prefix in out
diff --git a/packages/python/python-3.11-distutils-C++.patch b/packages/python/python-3.11-distutils-C++.patch
new file mode 100644
index 0000000000000000000000000000000000000000..335e06b93c3974d53be5551a0b0ac22255a25324
--- /dev/null
+++ b/packages/python/python-3.11-distutils-C++.patch
@@ -0,0 +1,257 @@
+diff --git a/Lib/_osx_support.py b/Lib/_osx_support.py
+index aa66c8b9f4..71e6556bac 100644
+--- a/Lib/_osx_support.py
++++ b/Lib/_osx_support.py
+@@ -14,13 +14,13 @@
+ # configuration variables that may contain universal build flags,
+ # like "-arch" or "-isdkroot", that may need customization for
+ # the user environment
+-_UNIVERSAL_CONFIG_VARS = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS', 'BASECFLAGS',
+-                            'BLDSHARED', 'LDSHARED', 'CC', 'CXX',
+-                            'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS',
+-                            'PY_CORE_CFLAGS', 'PY_CORE_LDFLAGS')
++_UNIVERSAL_CONFIG_VARS = ('CFLAGS', 'CXXFLAGS', 'LDFLAGS', 'CPPFLAGS',
++                          'BASECFLAGS', 'BLDSHARED', 'LDSHARED', 'LDCXXSHARED',
++                          'CC', 'CXX', 'PY_CFLAGS', 'PY_LDFLAGS',
++                          'PY_CPPFLAGS', 'PY_CORE_LDFLAGS', 'PY_CORE_CFLAGS')
+ 
+ # configuration variables that may contain compiler calls
+-_COMPILER_CONFIG_VARS = ('BLDSHARED', 'LDSHARED', 'CC', 'CXX')
++_COMPILER_CONFIG_VARS = ('BLDSHARED', 'LDSHARED', 'LDCXXSHARED', 'CC', 'CXX')
+ 
+ # prefix added to original configuration variable names
+ _INITPRE = '_OSX_SUPPORT_INITIAL_'
+diff --git a/Lib/distutils/cygwinccompiler.py b/Lib/distutils/cygwinccompiler.py
+index 66c12dd358..dddb9fd2d4 100644
+--- a/Lib/distutils/cygwinccompiler.py
++++ b/Lib/distutils/cygwinccompiler.py
+@@ -123,8 +123,10 @@ def __init__(self, verbose=0, dry_run=0, force=0):
+         # dllwrap 2.10.90 is buggy
+         if self.ld_version >= "2.10.90":
+             self.linker_dll = "gcc"
++            self.linker_dll_cxx = "g++"
+         else:
+             self.linker_dll = "dllwrap"
++            self.linker_dll_cxx = "dllwrap"
+ 
+         # ld_version >= "2.13" support -shared so use it instead of
+         # -mdll -static
+@@ -138,9 +140,13 @@ def __init__(self, verbose=0, dry_run=0, force=0):
+         self.set_executables(compiler='gcc -mcygwin -O -Wall',
+                              compiler_so='gcc -mcygwin -mdll -O -Wall',
+                              compiler_cxx='g++ -mcygwin -O -Wall',
++                             compiler_so_cxx='g++ -mcygwin -mdll -O -Wall',
+                              linker_exe='gcc -mcygwin',
+                              linker_so=('%s -mcygwin %s' %
+-                                        (self.linker_dll, shared_option)))
++                                        (self.linker_dll, shared_option)),
++                             linker_exe_cxx='g++ -mcygwin',
++                             linker_so_cxx=('%s -mcygwin %s' %
++                                            (self.linker_dll_cxx, shared_option)))
+ 
+         # cygwin and mingw32 need different sets of libraries
+         if self.gcc_version == "2.91.57":
+@@ -164,8 +170,12 @@ def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
+                 raise CompileError(msg)
+         else: # for other files use the C-compiler
+             try:
+-                self.spawn(self.compiler_so + cc_args + [src, '-o', obj] +
+-                           extra_postargs)
++                if self.detect_language(src) == 'c++':
++                    self.spawn(self.compiler_so_cxx + cc_args + [src, '-o', obj] +
++                               extra_postargs)
++                else:
++                    self.spawn(self.compiler_so + cc_args + [src, '-o', obj] +
++                               extra_postargs)
+             except DistutilsExecError as msg:
+                 raise CompileError(msg)
+ 
+@@ -300,9 +310,14 @@ def __init__(self, verbose=0, dry_run=0, force=0):
+         self.set_executables(compiler='gcc -O -Wall',
+                              compiler_so='gcc -mdll -O -Wall',
+                              compiler_cxx='g++ -O -Wall',
++                             compiler_so_cxx='g++ -mdll -O -Wall',
+                              linker_exe='gcc',
+                              linker_so='%s %s %s'
+                                         % (self.linker_dll, shared_option,
++                                           entry_point),
++                             linker_exe_cxx='g++',
++                             linker_so_cxx='%s %s %s'
++                                        % (self.linker_dll_cxx, shared_option,
+                                            entry_point))
+         # Maybe we should also append -mthreads, but then the finished
+         # dlls need another dll (mingwm10.dll see Mingw32 docs)
+diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py
+index 3414a761e7..f1af560cc1 100644
+--- a/Lib/distutils/sysconfig.py
++++ b/Lib/distutils/sysconfig.py
+@@ -216,9 +216,11 @@ def customize_compiler(compiler):
+                 _osx_support.customize_compiler(_config_vars)
+                 _config_vars['CUSTOMIZED_OSX_COMPILER'] = 'True'
+ 
+-        (cc, cxx, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags) = \
+-            get_config_vars('CC', 'CXX', 'CFLAGS',
+-                            'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS')
++        (cc, cxx, cflags, ccshared, ldshared, ldcxxshared, shlib_suffix, ar, ar_flags) = \
++            get_config_vars('CC', 'CXX', 'CFLAGS', 'CCSHARED', 'LDSHARED', 'LDCXXSHARED',
++                            'SHLIB_SUFFIX', 'AR', 'ARFLAGS')
++
++        cxxflags = cflags
+ 
+         if 'CC' in os.environ:
+             newcc = os.environ['CC']
+@@ -233,19 +235,27 @@ def customize_compiler(compiler):
+             cxx = os.environ['CXX']
+         if 'LDSHARED' in os.environ:
+             ldshared = os.environ['LDSHARED']
++        if 'LDCXXSHARED' in os.environ:
++            ldcxxshared = os.environ['LDCXXSHARED']
+         if 'CPP' in os.environ:
+             cpp = os.environ['CPP']
+         else:
+             cpp = cc + " -E"           # not always
+         if 'LDFLAGS' in os.environ:
+             ldshared = ldshared + ' ' + os.environ['LDFLAGS']
++            ldcxxshared = ldcxxshared + ' ' + os.environ['LDFLAGS']
+         if 'CFLAGS' in os.environ:
+-            cflags = cflags + ' ' + os.environ['CFLAGS']
++            cflags = os.environ['CFLAGS']
+             ldshared = ldshared + ' ' + os.environ['CFLAGS']
++        if 'CXXFLAGS' in os.environ:
++            cxxflags = os.environ['CXXFLAGS']
++            ldcxxshared = ldcxxshared + ' ' + os.environ['CXXFLAGS']
+         if 'CPPFLAGS' in os.environ:
+             cpp = cpp + ' ' + os.environ['CPPFLAGS']
+             cflags = cflags + ' ' + os.environ['CPPFLAGS']
++            cxxflags = cxxflags + ' ' + os.environ['CPPFLAGS']
+             ldshared = ldshared + ' ' + os.environ['CPPFLAGS']
++            ldcxxshared = ldcxxshared + ' ' + os.environ['CPPFLAGS']
+         if 'AR' in os.environ:
+             ar = os.environ['AR']
+         if 'ARFLAGS' in os.environ:
+@@ -254,13 +264,17 @@ def customize_compiler(compiler):
+             archiver = ar + ' ' + ar_flags
+ 
+         cc_cmd = cc + ' ' + cflags
++        cxx_cmd = cxx + ' ' + cxxflags
+         compiler.set_executables(
+             preprocessor=cpp,
+             compiler=cc_cmd,
+             compiler_so=cc_cmd + ' ' + ccshared,
+-            compiler_cxx=cxx,
++            compiler_cxx=cxx_cmd,
++            compiler_so_cxx=cxx_cmd + ' ' + ccshared,
+             linker_so=ldshared,
+             linker_exe=cc,
++            linker_so_cxx=ldcxxshared,
++            linker_exe_cxx=cxx,
+             archiver=archiver)
+ 
+         compiler.shared_lib_extension = shlib_suffix
+diff --git a/Lib/distutils/unixccompiler.py b/Lib/distutils/unixccompiler.py
+index d00c48981e..4a3d271fee 100644
+--- a/Lib/distutils/unixccompiler.py
++++ b/Lib/distutils/unixccompiler.py
+@@ -52,14 +52,17 @@ class UnixCCompiler(CCompiler):
+     # are pretty generic; they will probably have to be set by an outsider
+     # (eg. using information discovered by the sysconfig about building
+     # Python extensions).
+-    executables = {'preprocessor' : None,
+-                   'compiler'     : ["cc"],
+-                   'compiler_so'  : ["cc"],
+-                   'compiler_cxx' : ["cc"],
+-                   'linker_so'    : ["cc", "-shared"],
+-                   'linker_exe'   : ["cc"],
+-                   'archiver'     : ["ar", "-cr"],
+-                   'ranlib'       : None,
++    executables = {'preprocessor'    : None,
++                   'compiler'        : ["cc"],
++                   'compiler_so'     : ["cc"],
++                   'compiler_cxx'    : ["c++"],
++                   'compiler_so_cxx' : ["c++"],
++                   'linker_so'       : ["cc", "-shared"],
++                   'linker_exe'      : ["cc"],
++                   'linker_so_cxx'   : ["c++", "-shared"],
++                   'linker_exe_cxx'  : ["c++"],
++                   'archiver'        : ["ar", "-cr"],
++                   'ranlib'          : None,
+                   }
+ 
+     if sys.platform[:6] == "darwin":
+@@ -110,12 +113,19 @@ def preprocess(self, source, output_file=None, macros=None,
+ 
+     def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
+         compiler_so = self.compiler_so
++        compiler_so_cxx = self.compiler_so_cxx
+         if sys.platform == 'darwin':
+             compiler_so = _osx_support.compiler_fixup(compiler_so,
+                                                     cc_args + extra_postargs)
++            compiler_so_cxx = _osx_support.compiler_fixup(compiler_so_cxx,
++                                                    cc_args + extra_postargs)
+         try:
+-            self.spawn(compiler_so + cc_args + [src, '-o', obj] +
+-                       extra_postargs)
++            if self.detect_language(src) == 'c++':
++                self.spawn(compiler_so_cxx + cc_args + [src, '-o', obj] +
++                           extra_postargs)
++            else:
++                self.spawn(compiler_so + cc_args + [src, '-o', obj] +
++                           extra_postargs)
+         except DistutilsExecError as msg:
+             raise CompileError(msg)
+ 
+@@ -173,30 +183,16 @@ def link(self, target_desc, objects,
+                 ld_args.extend(extra_postargs)
+             self.mkpath(os.path.dirname(output_filename))
+             try:
+-                if target_desc == CCompiler.EXECUTABLE:
+-                    linker = self.linker_exe[:]
++                if target_lang == "c++":
++                    if target_desc == CCompiler.EXECUTABLE:
++                        linker = self.linker_exe_cxx[:]
++                    else:
++                        linker = self.linker_so_cxx[:]
+                 else:
+-                    linker = self.linker_so[:]
+-                if target_lang == "c++" and self.compiler_cxx:
+-                    # skip over environment variable settings if /usr/bin/env
+-                    # is used to set up the linker's environment.
+-                    # This is needed on OSX. Note: this assumes that the
+-                    # normal and C++ compiler have the same environment
+-                    # settings.
+-                    i = 0
+-                    if os.path.basename(linker[0]) == "env":
+-                        i = 1
+-                        while '=' in linker[i]:
+-                            i += 1
+-
+-                    if os.path.basename(linker[i]) == 'ld_so_aix':
+-                        # AIX platforms prefix the compiler with the ld_so_aix
+-                        # script, so we need to adjust our linker index
+-                        offset = 1
++                    if target_desc == CCompiler.EXECUTABLE:
++                        linker = self.linker_exe[:]
+                     else:
+-                        offset = 0
+-
+-                    linker[i+offset] = self.compiler_cxx[i]
++                        linker = self.linker_so[:]
+ 
+                 if sys.platform == 'darwin':
+                     linker = _osx_support.compiler_fixup(linker, ld_args)
+diff --git a/Makefile.pre.in b/Makefile.pre.in
+index f803391346..090f14c46c 100644
+--- a/Makefile.pre.in
++++ b/Makefile.pre.in
+@@ -732,9 +732,9 @@ sharedmods: $(BUILDPYTHON) pybuilddir.txt @LIBMPDEC_INTERNAL@ @LIBEXPAT_INTERNAL
+ 	    *\ -s*|s*) quiet="-q";; \
+ 	    *) quiet="";; \
+ 	esac; \
+-	echo "$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' \
++	echo "$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' CFLAGS='$(PY_CFLAGS)' \
+ 		$(PYTHON_FOR_BUILD) $(srcdir)/setup.py $$quiet build"; \
+-	$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' \
++	$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' CFLAGS='$(PY_CFLAGS)' \
+ 		$(PYTHON_FOR_BUILD) $(srcdir)/setup.py $$quiet build
+ 
+ 
diff --git a/packages/python/python-3.7.2-distutils-C++.patch b/packages/python/python-3.7.2-distutils-C++.patch
new file mode 100644
index 0000000000000000000000000000000000000000..5728fad6f77f331d8f8fee1ad97c742f27928980
--- /dev/null
+++ b/packages/python/python-3.7.2-distutils-C++.patch
@@ -0,0 +1,241 @@
+--- a/Lib/_osx_support.py
++++ b/Lib/_osx_support.py
+@@ -14,13 +14,13 @@ __all__ = [
+ # configuration variables that may contain universal build flags,
+ # like "-arch" or "-isdkroot", that may need customization for
+ # the user environment
+-_UNIVERSAL_CONFIG_VARS = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS', 'BASECFLAGS',
+-                            'BLDSHARED', 'LDSHARED', 'CC', 'CXX',
+-                            'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS',
+-                            'PY_CORE_CFLAGS', 'PY_CORE_LDFLAGS')
++_UNIVERSAL_CONFIG_VARS = ('CFLAGS', 'CXXFLAGS', 'LDFLAGS', 'CPPFLAGS',
++                          'BASECFLAGS', 'BLDSHARED', 'LDSHARED', 'LDCXXSHARED',
++                          'CC', 'CXX', 'PY_CFLAGS', 'PY_LDFLAGS',
++                          'PY_CPPFLAGS', 'PY_CORE_LDFLAGS', 'PY_CORE_CFLAGS')
+ 
+ # configuration variables that may contain compiler calls
+-_COMPILER_CONFIG_VARS = ('BLDSHARED', 'LDSHARED', 'CC', 'CXX')
++_COMPILER_CONFIG_VARS = ('BLDSHARED', 'LDSHARED', 'LDCXXSHARED', 'CC', 'CXX')
+ 
+ # prefix added to original configuration variable names
+ _INITPRE = '_OSX_SUPPORT_INITIAL_'
+--- a/Lib/distutils/cygwinccompiler.py
++++ b/Lib/distutils/cygwinccompiler.py
+@@ -125,8 +125,10 @@ class CygwinCCompiler(UnixCCompiler):
+         # dllwrap 2.10.90 is buggy
+         if self.ld_version >= "2.10.90":
+             self.linker_dll = "gcc"
++            self.linker_dll_cxx = "g++"
+         else:
+             self.linker_dll = "dllwrap"
++            self.linker_dll_cxx = "dllwrap"
+ 
+         # ld_version >= "2.13" support -shared so use it instead of
+         # -mdll -static
+@@ -140,9 +142,13 @@ class CygwinCCompiler(UnixCCompiler):
+         self.set_executables(compiler='gcc -mcygwin -O -Wall',
+                              compiler_so='gcc -mcygwin -mdll -O -Wall',
+                              compiler_cxx='g++ -mcygwin -O -Wall',
++                             compiler_so_cxx='g++ -mcygwin -mdll -O -Wall',
+                              linker_exe='gcc -mcygwin',
+                              linker_so=('%s -mcygwin %s' %
+-                                        (self.linker_dll, shared_option)))
++                                        (self.linker_dll, shared_option)),
++                             linker_exe_cxx='g++ -mcygwin',
++                             linker_so_cxx=('%s -mcygwin %s' %
++                                            (self.linker_dll_cxx, shared_option)))
+ 
+         # cygwin and mingw32 need different sets of libraries
+         if self.gcc_version == "2.91.57":
+@@ -166,8 +172,12 @@ class CygwinCCompiler(UnixCCompiler):
+                 raise CompileError(msg)
+         else: # for other files use the C-compiler
+             try:
+-                self.spawn(self.compiler_so + cc_args + [src, '-o', obj] +
+-                           extra_postargs)
++                if self.detect_language(src) == 'c++':
++                    self.spawn(self.compiler_so_cxx + cc_args + [src, '-o', obj] +
++                               extra_postargs)
++                else:
++                    self.spawn(self.compiler_so + cc_args + [src, '-o', obj] +
++                               extra_postargs)
+             except DistutilsExecError as msg:
+                 raise CompileError(msg)
+ 
+@@ -302,9 +312,14 @@ class Mingw32CCompiler(CygwinCCompiler):
+         self.set_executables(compiler='gcc -O -Wall',
+                              compiler_so='gcc -mdll -O -Wall',
+                              compiler_cxx='g++ -O -Wall',
++                             compiler_so_cxx='g++ -mdll -O -Wall',
+                              linker_exe='gcc',
+                              linker_so='%s %s %s'
+                                         % (self.linker_dll, shared_option,
++                                           entry_point),
++                             linker_exe_cxx='g++',
++                             linker_so_cxx='%s %s %s'
++                                        % (self.linker_dll_cxx, shared_option,
+                                            entry_point))
+         # Maybe we should also append -mthreads, but then the finished
+         # dlls need another dll (mingwm10.dll see Mingw32 docs)
+--- a/Lib/distutils/sysconfig.py
++++ b/Lib/distutils/sysconfig.py
+@@ -170,9 +170,11 @@ def customize_compiler(compiler):
+                 _osx_support.customize_compiler(_config_vars)
+                 _config_vars['CUSTOMIZED_OSX_COMPILER'] = 'True'
+ 
+-        (cc, cxx, opt, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags) = \
+-            get_config_vars('CC', 'CXX', 'OPT', 'CFLAGS',
+-                            'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS')
++        (cc, cxx, cflags, ccshared, ldshared, ldcxxshared, shlib_suffix, ar, ar_flags) = \
++            get_config_vars('CC', 'CXX', 'CFLAGS', 'CCSHARED', 'LDSHARED', 'LDCXXSHARED',
++                            'SHLIB_SUFFIX', 'AR', 'ARFLAGS')
++
++        cxxflags = cflags
+ 
+         if 'CC' in os.environ:
+             newcc = os.environ['CC']
+@@ -187,19 +189,27 @@ def customize_compiler(compiler):
+             cxx = os.environ['CXX']
+         if 'LDSHARED' in os.environ:
+             ldshared = os.environ['LDSHARED']
++        if 'LDCXXSHARED' in os.environ:
++            ldcxxshared = os.environ['LDCXXSHARED']
+         if 'CPP' in os.environ:
+             cpp = os.environ['CPP']
+         else:
+             cpp = cc + " -E"           # not always
+         if 'LDFLAGS' in os.environ:
+             ldshared = ldshared + ' ' + os.environ['LDFLAGS']
++            ldcxxshared = ldcxxshared + ' ' + os.environ['LDFLAGS']
+         if 'CFLAGS' in os.environ:
+-            cflags = opt + ' ' + os.environ['CFLAGS']
++            cflags = os.environ['CFLAGS']
+             ldshared = ldshared + ' ' + os.environ['CFLAGS']
++        if 'CXXFLAGS' in os.environ:
++            cxxflags = os.environ['CXXFLAGS']
++            ldcxxshared = ldcxxshared + ' ' + os.environ['CXXFLAGS']
+         if 'CPPFLAGS' in os.environ:
+             cpp = cpp + ' ' + os.environ['CPPFLAGS']
+             cflags = cflags + ' ' + os.environ['CPPFLAGS']
++            cxxflags = cxxflags + ' ' + os.environ['CPPFLAGS']
+             ldshared = ldshared + ' ' + os.environ['CPPFLAGS']
++            ldcxxshared = ldcxxshared + ' ' + os.environ['CPPFLAGS']
+         if 'AR' in os.environ:
+             ar = os.environ['AR']
+         if 'ARFLAGS' in os.environ:
+@@ -208,13 +218,17 @@ def customize_compiler(compiler):
+             archiver = ar + ' ' + ar_flags
+ 
+         cc_cmd = cc + ' ' + cflags
++        cxx_cmd = cxx + ' ' + cxxflags
+         compiler.set_executables(
+             preprocessor=cpp,
+             compiler=cc_cmd,
+             compiler_so=cc_cmd + ' ' + ccshared,
+-            compiler_cxx=cxx,
++            compiler_cxx=cxx_cmd,
++            compiler_so_cxx=cxx_cmd + ' ' + ccshared,
+             linker_so=ldshared,
+             linker_exe=cc,
++            linker_so_cxx=ldcxxshared,
++            linker_exe_cxx=cxx,
+             archiver=archiver)
+ 
+         compiler.shared_lib_extension = shlib_suffix
+--- a/Lib/distutils/unixccompiler.py
++++ b/Lib/distutils/unixccompiler.py
+@@ -52,14 +52,17 @@ class UnixCCompiler(CCompiler):
+     # are pretty generic; they will probably have to be set by an outsider
+     # (eg. using information discovered by the sysconfig about building
+     # Python extensions).
+-    executables = {'preprocessor' : None,
+-                   'compiler'     : ["cc"],
+-                   'compiler_so'  : ["cc"],
+-                   'compiler_cxx' : ["cc"],
+-                   'linker_so'    : ["cc", "-shared"],
+-                   'linker_exe'   : ["cc"],
+-                   'archiver'     : ["ar", "-cr"],
+-                   'ranlib'       : None,
++    executables = {'preprocessor'    : None,
++                   'compiler'        : ["cc"],
++                   'compiler_so'     : ["cc"],
++                   'compiler_cxx'    : ["c++"],
++                   'compiler_so_cxx' : ["c++"],
++                   'linker_so'       : ["cc", "-shared"],
++                   'linker_exe'      : ["cc"],
++                   'linker_so_cxx'   : ["c++", "-shared"],
++                   'linker_exe_cxx'  : ["c++"],
++                   'archiver'        : ["ar", "-cr"],
++                   'ranlib'          : None,
+                   }
+ 
+     if sys.platform[:6] == "darwin":
+@@ -110,12 +113,19 @@ class UnixCCompiler(CCompiler):
+ 
+     def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
+         compiler_so = self.compiler_so
++        compiler_so_cxx = self.compiler_so_cxx
+         if sys.platform == 'darwin':
+             compiler_so = _osx_support.compiler_fixup(compiler_so,
+                                                     cc_args + extra_postargs)
++            compiler_so_cxx = _osx_support.compiler_fixup(compiler_so_cxx,
++                                                    cc_args + extra_postargs)
+         try:
+-            self.spawn(compiler_so + cc_args + [src, '-o', obj] +
+-                       extra_postargs)
++            if self.detect_language(src) == 'c++':
++                self.spawn(compiler_so_cxx + cc_args + [src, '-o', obj] +
++                           extra_postargs)
++            else:
++                self.spawn(compiler_so + cc_args + [src, '-o', obj] +
++                           extra_postargs)
+         except DistutilsExecError as msg:
+             raise CompileError(msg)
+ 
+@@ -173,22 +183,16 @@ class UnixCCompiler(CCompiler):
+                 ld_args.extend(extra_postargs)
+             self.mkpath(os.path.dirname(output_filename))
+             try:
+-                if target_desc == CCompiler.EXECUTABLE:
+-                    linker = self.linker_exe[:]
++                if target_lang == "c++":
++                    if target_desc == CCompiler.EXECUTABLE:
++                        linker = self.linker_exe_cxx[:]
++                    else:
++                        linker = self.linker_so_cxx[:]
+                 else:
+-                    linker = self.linker_so[:]
+-                if target_lang == "c++" and self.compiler_cxx:
+-                    # skip over environment variable settings if /usr/bin/env
+-                    # is used to set up the linker's environment.
+-                    # This is needed on OSX. Note: this assumes that the
+-                    # normal and C++ compiler have the same environment
+-                    # settings.
+-                    i = 0
+-                    if os.path.basename(linker[0]) == "env":
+-                        i = 1
+-                        while '=' in linker[i]:
+-                            i += 1
+-                    linker[i] = self.compiler_cxx[i]
++                    if target_desc == CCompiler.EXECUTABLE:
++                        linker = self.linker_exe[:]
++                    else:
++                        linker = self.linker_so[:]
+ 
+                 if sys.platform == 'darwin':
+                     linker = _osx_support.compiler_fixup(linker, ld_args)
+--- a/Makefile.pre.in
++++ b/Makefile.pre.in
+@@ -584,10 +584,10 @@ sharedmods: $(BUILDPYTHON) pybuilddir.txt Modules/_math.o
+ 	    *\ -s*|s*) quiet="-q";; \
+ 	    *) quiet="";; \
+ 	esac; \
+-	echo "$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' \
++	echo "$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' CFLAGS='$(PY_CFLAGS)' \
+ 		_TCLTK_INCLUDES='$(TCLTK_INCLUDES)' _TCLTK_LIBS='$(TCLTK_LIBS)' \
+ 		$(PYTHON_FOR_BUILD) $(srcdir)/setup.py $$quiet build"; \
+-	$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' \
++	$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' CFLAGS='$(PY_CFLAGS)' \
+ 		_TCLTK_INCLUDES='$(TCLTK_INCLUDES)' _TCLTK_LIBS='$(TCLTK_LIBS)' \
+ 		$(PYTHON_FOR_BUILD) $(srcdir)/setup.py $$quiet build
+ 
diff --git a/packages/python/python-3.7.3-distutils-C++.patch b/packages/python/python-3.7.3-distutils-C++.patch
new file mode 100644
index 0000000000000000000000000000000000000000..e29323bf0b51b3c02a2816adfdd67cffbf66a8e7
--- /dev/null
+++ b/packages/python/python-3.7.3-distutils-C++.patch
@@ -0,0 +1,256 @@
+diff --git a/Lib/_osx_support.py b/Lib/_osx_support.py
+index db6674e..ccbe09a 100644
+--- a/Lib/_osx_support.py
++++ b/Lib/_osx_support.py
+@@ -14,13 +14,13 @@ __all__ = [
+ # configuration variables that may contain universal build flags,
+ # like "-arch" or "-isdkroot", that may need customization for
+ # the user environment
+-_UNIVERSAL_CONFIG_VARS = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS', 'BASECFLAGS',
+-                            'BLDSHARED', 'LDSHARED', 'CC', 'CXX',
+-                            'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS',
+-                            'PY_CORE_CFLAGS', 'PY_CORE_LDFLAGS')
++_UNIVERSAL_CONFIG_VARS = ('CFLAGS', 'CXXFLAGS', 'LDFLAGS', 'CPPFLAGS',
++                          'BASECFLAGS', 'BLDSHARED', 'LDSHARED', 'LDCXXSHARED',
++                          'CC', 'CXX', 'PY_CFLAGS', 'PY_LDFLAGS',
++                          'PY_CPPFLAGS', 'PY_CORE_LDFLAGS', 'PY_CORE_CFLAGS')
+ 
+ # configuration variables that may contain compiler calls
+-_COMPILER_CONFIG_VARS = ('BLDSHARED', 'LDSHARED', 'CC', 'CXX')
++_COMPILER_CONFIG_VARS = ('BLDSHARED', 'LDSHARED', 'LDCXXSHARED', 'CC', 'CXX')
+ 
+ # prefix added to original configuration variable names
+ _INITPRE = '_OSX_SUPPORT_INITIAL_'
+diff --git a/Lib/distutils/cygwinccompiler.py b/Lib/distutils/cygwinccompiler.py
+index 6c5d777..640fa2d 100644
+--- a/Lib/distutils/cygwinccompiler.py
++++ b/Lib/distutils/cygwinccompiler.py
+@@ -125,8 +125,10 @@ class CygwinCCompiler(UnixCCompiler):
+         # dllwrap 2.10.90 is buggy
+         if self.ld_version >= "2.10.90":
+             self.linker_dll = "gcc"
++            self.linker_dll_cxx = "g++"
+         else:
+             self.linker_dll = "dllwrap"
++            self.linker_dll_cxx = "dllwrap"
+ 
+         # ld_version >= "2.13" support -shared so use it instead of
+         # -mdll -static
+@@ -140,9 +142,13 @@ class CygwinCCompiler(UnixCCompiler):
+         self.set_executables(compiler='gcc -mcygwin -O -Wall',
+                              compiler_so='gcc -mcygwin -mdll -O -Wall',
+                              compiler_cxx='g++ -mcygwin -O -Wall',
++                             compiler_so_cxx='g++ -mcygwin -mdll -O -Wall',
+                              linker_exe='gcc -mcygwin',
+                              linker_so=('%s -mcygwin %s' %
+-                                        (self.linker_dll, shared_option)))
++                                        (self.linker_dll, shared_option)),
++                             linker_exe_cxx='g++ -mcygwin',
++                             linker_so_cxx=('%s -mcygwin %s' %
++                                            (self.linker_dll_cxx, shared_option)))
+ 
+         # cygwin and mingw32 need different sets of libraries
+         if self.gcc_version == "2.91.57":
+@@ -166,8 +172,12 @@ class CygwinCCompiler(UnixCCompiler):
+                 raise CompileError(msg)
+         else: # for other files use the C-compiler
+             try:
+-                self.spawn(self.compiler_so + cc_args + [src, '-o', obj] +
+-                           extra_postargs)
++                if self.detect_language(src) == 'c++':
++                    self.spawn(self.compiler_so_cxx + cc_args + [src, '-o', obj] +
++                               extra_postargs)
++                else:
++                    self.spawn(self.compiler_so + cc_args + [src, '-o', obj] +
++                               extra_postargs)
+             except DistutilsExecError as msg:
+                 raise CompileError(msg)
+ 
+@@ -302,9 +312,14 @@ class Mingw32CCompiler(CygwinCCompiler):
+         self.set_executables(compiler='gcc -O -Wall',
+                              compiler_so='gcc -mdll -O -Wall',
+                              compiler_cxx='g++ -O -Wall',
++                             compiler_so_cxx='g++ -mdll -O -Wall',
+                              linker_exe='gcc',
+                              linker_so='%s %s %s'
+                                         % (self.linker_dll, shared_option,
++                                           entry_point),
++                             linker_exe_cxx='g++',
++                             linker_so_cxx='%s %s %s'
++                                        % (self.linker_dll_cxx, shared_option,
+                                            entry_point))
+         # Maybe we should also append -mthreads, but then the finished
+         # dlls need another dll (mingwm10.dll see Mingw32 docs)
+diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py
+index 83160f8..b735369 100644
+--- a/Lib/distutils/sysconfig.py
++++ b/Lib/distutils/sysconfig.py
+@@ -183,9 +183,11 @@ def customize_compiler(compiler):
+                 _osx_support.customize_compiler(_config_vars)
+                 _config_vars['CUSTOMIZED_OSX_COMPILER'] = 'True'
+ 
+-        (cc, cxx, opt, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags) = \
++        (cc, cxx, opt, cflags, ccshared, ldshared, ldcxxshared, shlib_suffix, ar, ar_flags) = \
+             get_config_vars('CC', 'CXX', 'OPT', 'CFLAGS',
+-                            'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS')
++                            'CCSHARED', 'LDSHARED', 'LDCXXSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS')
++
++        cxxflags = cflags
+ 
+         if 'CC' in os.environ:
+             newcc = os.environ['CC']
+@@ -200,19 +202,27 @@ def customize_compiler(compiler):
+             cxx = os.environ['CXX']
+         if 'LDSHARED' in os.environ:
+             ldshared = os.environ['LDSHARED']
++        if 'LDCXXSHARED' in os.environ:
++            ldcxxshared = os.environ['LDCXXSHARED']
+         if 'CPP' in os.environ:
+             cpp = os.environ['CPP']
+         else:
+             cpp = cc + " -E"           # not always
+         if 'LDFLAGS' in os.environ:
+             ldshared = ldshared + ' ' + os.environ['LDFLAGS']
++            ldcxxshared = ldcxxshared + ' ' + os.environ['LDFLAGS']
+         if 'CFLAGS' in os.environ:
+             cflags = opt + ' ' + os.environ['CFLAGS']
+             ldshared = ldshared + ' ' + os.environ['CFLAGS']
++        if 'CXXFLAGS' in os.environ:
++            cxxflags = opt + ' ' + os.environ['CXXFLAGS']
++            ldcxxshared = ldcxxshared + ' ' + os.environ['CXXFLAGS']
+         if 'CPPFLAGS' in os.environ:
+             cpp = cpp + ' ' + os.environ['CPPFLAGS']
++            cxxflags = cxxflags + ' ' + os.environ['CPPFLAGS']
+             cflags = cflags + ' ' + os.environ['CPPFLAGS']
+             ldshared = ldshared + ' ' + os.environ['CPPFLAGS']
++            ldcxxshared = ldcxxshared + ' ' + os.environ['CPPFLAGS']
+         if 'AR' in os.environ:
+             ar = os.environ['AR']
+         if 'ARFLAGS' in os.environ:
+@@ -221,13 +231,17 @@ def customize_compiler(compiler):
+             archiver = ar + ' ' + ar_flags
+ 
+         cc_cmd = cc + ' ' + cflags
++        cxx_cmd = cxx + ' ' + cxxflags
+         compiler.set_executables(
+             preprocessor=cpp,
+             compiler=cc_cmd,
+             compiler_so=cc_cmd + ' ' + ccshared,
+-            compiler_cxx=cxx,
++            compiler_cxx=cxx_cmd,
++            compiler_so_cxx=cxx_cmd + ' ' + ccshared,
+             linker_so=ldshared,
+             linker_exe=cc,
++            linker_so_cxx=ldcxxshared,
++            linker_exe_cxx=cxx,
+             archiver=archiver)
+ 
+         compiler.shared_lib_extension = shlib_suffix
+diff --git a/Lib/distutils/unixccompiler.py b/Lib/distutils/unixccompiler.py
+index d10a78d..7e88781 100644
+--- a/Lib/distutils/unixccompiler.py
++++ b/Lib/distutils/unixccompiler.py
+@@ -52,14 +52,17 @@ class UnixCCompiler(CCompiler):
+     # are pretty generic; they will probably have to be set by an outsider
+     # (eg. using information discovered by the sysconfig about building
+     # Python extensions).
+-    executables = {'preprocessor' : None,
+-                   'compiler'     : ["cc"],
+-                   'compiler_so'  : ["cc"],
+-                   'compiler_cxx' : ["cc"],
+-                   'linker_so'    : ["cc", "-shared"],
+-                   'linker_exe'   : ["cc"],
+-                   'archiver'     : ["ar", "-cr"],
+-                   'ranlib'       : None,
++    executables = {'preprocessor'    : None,
++                   'compiler'        : ["cc"],
++                   'compiler_so'     : ["cc"],
++                   'compiler_cxx'    : ["c++"],
++                   'compiler_so_cxx' : ["c++"],
++                   'linker_so'       : ["cc", "-shared"],
++                   'linker_exe'      : ["cc"],
++                   'linker_so_cxx'   : ["c++", "-shared"],
++                   'linker_exe_cxx'  : ["c++"],
++                   'archiver'        : ["ar", "-cr"],
++                   'ranlib'          : None,
+                   }
+ 
+     if sys.platform[:6] == "darwin":
+@@ -110,12 +113,19 @@ class UnixCCompiler(CCompiler):
+ 
+     def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
+         compiler_so = self.compiler_so
++        compiler_so_cxx = self.compiler_so_cxx
+         if sys.platform == 'darwin':
+             compiler_so = _osx_support.compiler_fixup(compiler_so,
+                                                     cc_args + extra_postargs)
++            compiler_so_cxx = _osx_support.compiler_fixup(compiler_so_cxx,
++                                                    cc_args + extra_postargs)
+         try:
+-            self.spawn(compiler_so + cc_args + [src, '-o', obj] +
+-                       extra_postargs)
++            if self.detect_language(src) == 'c++':
++                self.spawn(compiler_so_cxx + cc_args + [src, '-o', obj] +
++                           extra_postargs)
++            else:
++                self.spawn(compiler_so + cc_args + [src, '-o', obj] +
++                           extra_postargs)
+         except DistutilsExecError as msg:
+             raise CompileError(msg)
+ 
+@@ -173,30 +183,16 @@ class UnixCCompiler(CCompiler):
+                 ld_args.extend(extra_postargs)
+             self.mkpath(os.path.dirname(output_filename))
+             try:
+-                if target_desc == CCompiler.EXECUTABLE:
+-                    linker = self.linker_exe[:]
++                if target_lang == "c++":
++                    if target_desc == CCompiler.EXECUTABLE:
++                        linker = self.linker_exe_cxx[:]
++                    else:
++                        linker = self.linker_so_cxx[:]
+                 else:
+-                    linker = self.linker_so[:]
+-                if target_lang == "c++" and self.compiler_cxx:
+-                    # skip over environment variable settings if /usr/bin/env
+-                    # is used to set up the linker's environment.
+-                    # This is needed on OSX. Note: this assumes that the
+-                    # normal and C++ compiler have the same environment
+-                    # settings.
+-                    i = 0
+-                    if os.path.basename(linker[0]) == "env":
+-                        i = 1
+-                        while '=' in linker[i]:
+-                            i += 1
+-
+-                    if os.path.basename(linker[i]) == 'ld_so_aix':
+-                        # AIX platforms prefix the compiler with the ld_so_aix
+-                        # script, so we need to adjust our linker index
+-                        offset = 1
++                    if target_desc == CCompiler.EXECUTABLE:
++                        linker = self.linker_exe[:]
+                     else:
+-                        offset = 0
+-
+-                    linker[i+offset] = self.compiler_cxx[i]
++                        linker = self.linker_so[:]
+ 
+                 if sys.platform == 'darwin':
+                     linker = _osx_support.compiler_fixup(linker, ld_args)
+diff --git a/Makefile.pre.in b/Makefile.pre.in
+index 2d2e11f..8456e3f 100644
+--- a/Makefile.pre.in
++++ b/Makefile.pre.in
+@@ -615,10 +615,10 @@ sharedmods: $(BUILDPYTHON) pybuilddir.txt Modules/_math.o
+ 	    *\ -s*|s*) quiet="-q";; \
+ 	    *) quiet="";; \
+ 	esac; \
+-	echo "$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' \
++	echo "$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' CFLAGS='$(PY_CFLAGS)' \
+ 		_TCLTK_INCLUDES='$(TCLTK_INCLUDES)' _TCLTK_LIBS='$(TCLTK_LIBS)' \
+ 		$(PYTHON_FOR_BUILD) $(srcdir)/setup.py $$quiet build"; \
+-	$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' \
++	$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' CFLAGS='$(PY_CFLAGS)' \
+ 		_TCLTK_INCLUDES='$(TCLTK_INCLUDES)' _TCLTK_LIBS='$(TCLTK_LIBS)' \
+ 		$(PYTHON_FOR_BUILD) $(srcdir)/setup.py $$quiet build
+ 
diff --git a/packages/python/python-3.7.4+-distutils-C++-testsuite.patch b/packages/python/python-3.7.4+-distutils-C++-testsuite.patch
new file mode 100644
index 0000000000000000000000000000000000000000..99361087024d26c6145ebad6f6c49032910a51f7
--- /dev/null
+++ b/packages/python/python-3.7.4+-distutils-C++-testsuite.patch
@@ -0,0 +1,138 @@
+This patch updates the distutils test suite for:
+var/spack/repos/builtin/packages/python/python-3.7.4+-distutils-C++.patch
+
+That patch fixes several shortcomings in the distutils C++ support,
+most prominently missing support for passing CXXFLAGS from the environment.
+
+Since it does not update the distutils testsuite, it causes the testsuite
+to fail, which this patch updates to pass.
+
+-----------------------------------------------------------------------------
+Spack changelog
+- Added patch header to aid understanding the patch and maintainance
+- Updated the distutils testsuite in Lib/distutils/tests/test_sysconfig.py
+
+-----------------------------------------------------------------------------
+Upstream status
+
+Upstream bug: https://bugs.python.org/issue1222585
+
+Status: Closed, wont fix, comment by Eric Araujo, Python Core Dev:
+"setuptools and other active build tools are the better target for this feature."
+https://bugs.python.org/issue1222585#msg379348
+
+But according to the last-but-oncomment, setuptools seems to be lacking there too.
+https://bugs.python.org/issue1222585#msg371840
+
+-----------------------------------------------------------------------------
+Description
+
+distutils has no support for CXXFLAGS, this patch adds it.
+
+Upstream distutils requires to pass all CXXFLAGS (C++-specific CFLAGS)
+as part of the CXX enviromnent variable instead.
+
+This patch:
+- adds CXXFLAGS support
+- adds LDCXXSHARED like LDSHARED
+- passes cflags to CXX like it passes them to CC.
+
+The distutils testsuite is updated accordingly to pass the tests.
+Since it passes, it is the authoritative info of the current effects of this patch.
+
+See the update of the distutils testsuite in Lib/distutils/tests/test_sysconfig.py
+below for details on the effect of this patch.
+
+diff --git a/Lib/distutils/tests/test_sysconfig.py b/Lib/distutils/tests/test_sysconfig.py
+index db6674e..ccbe09a 100644
+--- a/Lib/distutils/tests/test_sysconfig.py
++++ b/Lib/distutils/tests/test_sysconfig.py
+@@ -89,8 +89,10 @@
+             'CXX': 'sc_cxx',
+             'ARFLAGS': '--sc-arflags',
+             'CFLAGS': '--sc-cflags',
++            'CXXFLAGS': '--sc-cxxflags',
+             'CCSHARED': '--sc-ccshared',
+             'LDSHARED': 'sc_ldshared',
++            'LDCXXSHARED': 'sc_ldshared_cxx',
+             'SHLIB_SUFFIX': 'sc_shutil_suffix',
+ 
+             # On macOS, disable _osx_support.customize_compiler()
+@@ -114,11 +116,13 @@
+         os.environ['AR'] = 'env_ar'
+         os.environ['CC'] = 'env_cc'
+         os.environ['CPP'] = 'env_cpp'
+-        os.environ['CXX'] = 'env_cxx --env-cxx-flags'
++        os.environ['CXX'] = 'env_cxx'
+         os.environ['LDSHARED'] = 'env_ldshared'
++        os.environ['LDCXXSHARED'] = 'env_ldshared_cxx'
+         os.environ['LDFLAGS'] = '--env-ldflags'
+         os.environ['ARFLAGS'] = '--env-arflags'
+         os.environ['CFLAGS'] = '--env-cflags'
++        os.environ['CXXFLAGS'] = '--env-cxxflags'
+         os.environ['CPPFLAGS'] = '--env-cppflags'
+ 
+         comp = self.customize_compiler()
+@@ -128,16 +132,24 @@
+                          'env_cpp --env-cppflags')
+         self.assertEqual(comp.exes['compiler'],
+                          'env_cc --sc-cflags --env-cflags --env-cppflags')
++        self.assertEqual(comp.exes['compiler_cxx'],
++                         'env_cxx --sc-cflags --env-cxxflags --env-cppflags')
+         self.assertEqual(comp.exes['compiler_so'],
+                          ('env_cc --sc-cflags '
+                           '--env-cflags ''--env-cppflags --sc-ccshared'))
+-        self.assertEqual(comp.exes['compiler_cxx'],
+-                         'env_cxx --env-cxx-flags')
++        self.assertEqual(comp.exes['compiler_so_cxx'],
++                         ('env_cxx --sc-cflags '
++                          '--env-cxxflags ''--env-cppflags --sc-ccshared'))
+         self.assertEqual(comp.exes['linker_exe'],
+                          'env_cc')
++        self.assertEqual(comp.exes['linker_exe_cxx'],
++                         'env_cxx')
+         self.assertEqual(comp.exes['linker_so'],
+                          ('env_ldshared --env-ldflags --env-cflags'
+                           ' --env-cppflags'))
++        self.assertEqual(comp.exes['linker_so_cxx'],
++                         ('env_ldshared_cxx --env-ldflags --env-cxxflags'
++                          ' --env-cppflags'))
+         self.assertEqual(comp.shared_lib_extension, 'sc_shutil_suffix')
+ 
+         del os.environ['AR']
+@@ -145,9 +157,11 @@
+         del os.environ['CPP']
+         del os.environ['CXX']
+         del os.environ['LDSHARED']
++        del os.environ['LDCXXSHARED']
+         del os.environ['LDFLAGS']
+         del os.environ['ARFLAGS']
+         del os.environ['CFLAGS']
++        del os.environ['CXXFLAGS']
+         del os.environ['CPPFLAGS']
+ 
+         comp = self.customize_compiler()
+@@ -157,14 +171,21 @@
+                          'sc_cc -E')
+         self.assertEqual(comp.exes['compiler'],
+                          'sc_cc --sc-cflags')
++        # TODO: Likely this sould get --sc-cxxflags instead:
++        self.assertEqual(comp.exes['compiler_cxx'],
++                         'sc_cxx --sc-cflags')
+         self.assertEqual(comp.exes['compiler_so'],
+                          'sc_cc --sc-cflags --sc-ccshared')
+-        self.assertEqual(comp.exes['compiler_cxx'],
+-                         'sc_cxx')
++        self.assertEqual(comp.exes['compiler_so_cxx'],
++                         'sc_cxx --sc-cflags --sc-ccshared')
+         self.assertEqual(comp.exes['linker_exe'],
+                          'sc_cc')
++        self.assertEqual(comp.exes['linker_exe_cxx'],
++                         'sc_cxx')
+         self.assertEqual(comp.exes['linker_so'],
+                          'sc_ldshared')
++        self.assertEqual(comp.exes['linker_so_cxx'],
++                         'sc_ldshared_cxx')
+         self.assertEqual(comp.shared_lib_extension, 'sc_shutil_suffix')
+ 
+     def test_parse_makefile_base(self):
diff --git a/packages/python/python-3.7.4+-distutils-C++.patch b/packages/python/python-3.7.4+-distutils-C++.patch
new file mode 100644
index 0000000000000000000000000000000000000000..02daf0a11bfbb0b004812992f0bcb64db6a59380
--- /dev/null
+++ b/packages/python/python-3.7.4+-distutils-C++.patch
@@ -0,0 +1,257 @@
+diff --git a/Lib/_osx_support.py b/Lib/_osx_support.py
+index db6674e..ccbe09a 100644
+--- a/Lib/_osx_support.py
++++ b/Lib/_osx_support.py
+@@ -14,13 +14,13 @@ __all__ = [
+ # configuration variables that may contain universal build flags,
+ # like "-arch" or "-isdkroot", that may need customization for
+ # the user environment
+-_UNIVERSAL_CONFIG_VARS = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS', 'BASECFLAGS',
+-                            'BLDSHARED', 'LDSHARED', 'CC', 'CXX',
+-                            'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS',
+-                            'PY_CORE_CFLAGS', 'PY_CORE_LDFLAGS')
++_UNIVERSAL_CONFIG_VARS = ('CFLAGS', 'CXXFLAGS', 'LDFLAGS', 'CPPFLAGS',
++                          'BASECFLAGS', 'BLDSHARED', 'LDSHARED', 'LDCXXSHARED',
++                          'CC', 'CXX', 'PY_CFLAGS', 'PY_LDFLAGS',
++                          'PY_CPPFLAGS', 'PY_CORE_LDFLAGS', 'PY_CORE_CFLAGS')
+ 
+ # configuration variables that may contain compiler calls
+-_COMPILER_CONFIG_VARS = ('BLDSHARED', 'LDSHARED', 'CC', 'CXX')
++_COMPILER_CONFIG_VARS = ('BLDSHARED', 'LDSHARED', 'LDCXXSHARED', 'CC', 'CXX')
+ 
+ # prefix added to original configuration variable names
+ _INITPRE = '_OSX_SUPPORT_INITIAL_'
+diff --git a/Lib/distutils/cygwinccompiler.py b/Lib/distutils/cygwinccompiler.py
+index 6c5d777..640fa2d 100644
+--- a/Lib/distutils/cygwinccompiler.py
++++ b/Lib/distutils/cygwinccompiler.py
+@@ -125,8 +125,10 @@ class CygwinCCompiler(UnixCCompiler):
+         # dllwrap 2.10.90 is buggy
+         if self.ld_version >= "2.10.90":
+             self.linker_dll = "gcc"
++            self.linker_dll_cxx = "g++"
+         else:
+             self.linker_dll = "dllwrap"
++            self.linker_dll_cxx = "dllwrap"
+ 
+         # ld_version >= "2.13" support -shared so use it instead of
+         # -mdll -static
+@@ -140,9 +142,13 @@ class CygwinCCompiler(UnixCCompiler):
+         self.set_executables(compiler='gcc -mcygwin -O -Wall',
+                              compiler_so='gcc -mcygwin -mdll -O -Wall',
+                              compiler_cxx='g++ -mcygwin -O -Wall',
++                             compiler_so_cxx='g++ -mcygwin -mdll -O -Wall',
+                              linker_exe='gcc -mcygwin',
+                              linker_so=('%s -mcygwin %s' %
+-                                        (self.linker_dll, shared_option)))
++                                        (self.linker_dll, shared_option)),
++                             linker_exe_cxx='g++ -mcygwin',
++                             linker_so_cxx=('%s -mcygwin %s' %
++                                            (self.linker_dll_cxx, shared_option)))
+ 
+         # cygwin and mingw32 need different sets of libraries
+         if self.gcc_version == "2.91.57":
+@@ -166,8 +172,12 @@ class CygwinCCompiler(UnixCCompiler):
+                 raise CompileError(msg)
+         else: # for other files use the C-compiler
+             try:
+-                self.spawn(self.compiler_so + cc_args + [src, '-o', obj] +
+-                           extra_postargs)
++                if self.detect_language(src) == 'c++':
++                    self.spawn(self.compiler_so_cxx + cc_args + [src, '-o', obj] +
++                               extra_postargs)
++                else:
++                    self.spawn(self.compiler_so + cc_args + [src, '-o', obj] +
++                               extra_postargs)
+             except DistutilsExecError as msg:
+                 raise CompileError(msg)
+ 
+@@ -302,9 +312,14 @@ class Mingw32CCompiler(CygwinCCompiler):
+         self.set_executables(compiler='gcc -O -Wall',
+                              compiler_so='gcc -mdll -O -Wall',
+                              compiler_cxx='g++ -O -Wall',
++                             compiler_so_cxx='g++ -mdll -O -Wall',
+                              linker_exe='gcc',
+                              linker_so='%s %s %s'
+                                         % (self.linker_dll, shared_option,
++                                           entry_point),
++                             linker_exe_cxx='g++',
++                             linker_so_cxx='%s %s %s'
++                                        % (self.linker_dll_cxx, shared_option,
+                                            entry_point))
+         # Maybe we should also append -mthreads, but then the finished
+         # dlls need another dll (mingwm10.dll see Mingw32 docs)
+diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py
+index 0a034ee..ecf4759 100644
+--- a/Lib/distutils/sysconfig.py
++++ b/Lib/distutils/sysconfig.py
+@@ -188,9 +188,11 @@ def customize_compiler(compiler):
+                 _osx_support.customize_compiler(_config_vars)
+                 _config_vars['CUSTOMIZED_OSX_COMPILER'] = 'True'
+ 
+-        (cc, cxx, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags) = \
+-            get_config_vars('CC', 'CXX', 'CFLAGS',
+-                            'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS')
++        (cc, cxx, cflags, ccshared, ldshared, ldcxxshared, shlib_suffix, ar, ar_flags) = \
++            get_config_vars('CC', 'CXX', 'CFLAGS', 'CCSHARED', 'LDSHARED', 'LDCXXSHARED',
++                            'SHLIB_SUFFIX', 'AR', 'ARFLAGS')
++
++        cxxflags = cflags
+ 
+         if 'CC' in os.environ:
+             newcc = os.environ['CC']
+@@ -205,19 +207,27 @@ def customize_compiler(compiler):
+             cxx = os.environ['CXX']
+         if 'LDSHARED' in os.environ:
+             ldshared = os.environ['LDSHARED']
++        if 'LDCXXSHARED' in os.environ:
++            ldcxxshared = os.environ['LDCXXSHARED']
+         if 'CPP' in os.environ:
+             cpp = os.environ['CPP']
+         else:
+             cpp = cc + " -E"           # not always
+         if 'LDFLAGS' in os.environ:
+             ldshared = ldshared + ' ' + os.environ['LDFLAGS']
++            ldcxxshared = ldcxxshared + ' ' + os.environ['LDFLAGS']
+         if 'CFLAGS' in os.environ:
+             cflags = cflags + ' ' + os.environ['CFLAGS']
+             ldshared = ldshared + ' ' + os.environ['CFLAGS']
++        if 'CXXFLAGS' in os.environ:
++            cxxflags = cxxflags + ' ' + os.environ['CXXFLAGS']
++            ldcxxshared = ldcxxshared + ' ' + os.environ['CXXFLAGS']
+         if 'CPPFLAGS' in os.environ:
+             cpp = cpp + ' ' + os.environ['CPPFLAGS']
+             cflags = cflags + ' ' + os.environ['CPPFLAGS']
++            cxxflags = cxxflags + ' ' + os.environ['CPPFLAGS']
+             ldshared = ldshared + ' ' + os.environ['CPPFLAGS']
++            ldcxxshared = ldcxxshared + ' ' + os.environ['CPPFLAGS']
+         if 'AR' in os.environ:
+             ar = os.environ['AR']
+         if 'ARFLAGS' in os.environ:
+@@ -226,13 +236,17 @@ def customize_compiler(compiler):
+             archiver = ar + ' ' + ar_flags
+ 
+         cc_cmd = cc + ' ' + cflags
++        cxx_cmd = cxx + ' ' + cxxflags
+         compiler.set_executables(
+             preprocessor=cpp,
+             compiler=cc_cmd,
+             compiler_so=cc_cmd + ' ' + ccshared,
+-            compiler_cxx=cxx,
++            compiler_cxx=cxx_cmd,
++            compiler_so_cxx=cxx_cmd + ' ' + ccshared,
+             linker_so=ldshared,
+             linker_exe=cc,
++            linker_so_cxx=ldcxxshared,
++            linker_exe_cxx=cxx,
+             archiver=archiver)
+ 
+         compiler.shared_lib_extension = shlib_suffix
+diff --git a/Lib/distutils/unixccompiler.py b/Lib/distutils/unixccompiler.py
+index d10a78d..7e88781 100644
+--- a/Lib/distutils/unixccompiler.py
++++ b/Lib/distutils/unixccompiler.py
+@@ -52,14 +52,17 @@ class UnixCCompiler(CCompiler):
+     # are pretty generic; they will probably have to be set by an outsider
+     # (eg. using information discovered by the sysconfig about building
+     # Python extensions).
+-    executables = {'preprocessor' : None,
+-                   'compiler'     : ["cc"],
+-                   'compiler_so'  : ["cc"],
+-                   'compiler_cxx' : ["cc"],
+-                   'linker_so'    : ["cc", "-shared"],
+-                   'linker_exe'   : ["cc"],
+-                   'archiver'     : ["ar", "-cr"],
+-                   'ranlib'       : None,
++    executables = {'preprocessor'    : None,
++                   'compiler'        : ["cc"],
++                   'compiler_so'     : ["cc"],
++                   'compiler_cxx'    : ["c++"],
++                   'compiler_so_cxx' : ["c++"],
++                   'linker_so'       : ["cc", "-shared"],
++                   'linker_exe'      : ["cc"],
++                   'linker_so_cxx'   : ["c++", "-shared"],
++                   'linker_exe_cxx'  : ["c++"],
++                   'archiver'        : ["ar", "-cr"],
++                   'ranlib'          : None,
+                   }
+ 
+     if sys.platform[:6] == "darwin":
+@@ -110,12 +113,19 @@ class UnixCCompiler(CCompiler):
+ 
+     def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
+         compiler_so = self.compiler_so
++        compiler_so_cxx = self.compiler_so_cxx
+         if sys.platform == 'darwin':
+             compiler_so = _osx_support.compiler_fixup(compiler_so,
+                                                     cc_args + extra_postargs)
++            compiler_so_cxx = _osx_support.compiler_fixup(compiler_so_cxx,
++                                                    cc_args + extra_postargs)
+         try:
+-            self.spawn(compiler_so + cc_args + [src, '-o', obj] +
+-                       extra_postargs)
++            if self.detect_language(src) == 'c++':
++                self.spawn(compiler_so_cxx + cc_args + [src, '-o', obj] +
++                           extra_postargs)
++            else:
++                self.spawn(compiler_so + cc_args + [src, '-o', obj] +
++                           extra_postargs)
+         except DistutilsExecError as msg:
+             raise CompileError(msg)
+ 
+@@ -173,30 +183,16 @@ class UnixCCompiler(CCompiler):
+                 ld_args.extend(extra_postargs)
+             self.mkpath(os.path.dirname(output_filename))
+             try:
+-                if target_desc == CCompiler.EXECUTABLE:
+-                    linker = self.linker_exe[:]
++                if target_lang == "c++":
++                    if target_desc == CCompiler.EXECUTABLE:
++                        linker = self.linker_exe_cxx[:]
++                    else:
++                        linker = self.linker_so_cxx[:]
+                 else:
+-                    linker = self.linker_so[:]
+-                if target_lang == "c++" and self.compiler_cxx:
+-                    # skip over environment variable settings if /usr/bin/env
+-                    # is used to set up the linker's environment.
+-                    # This is needed on OSX. Note: this assumes that the
+-                    # normal and C++ compiler have the same environment
+-                    # settings.
+-                    i = 0
+-                    if os.path.basename(linker[0]) == "env":
+-                        i = 1
+-                        while '=' in linker[i]:
+-                            i += 1
+-
+-                    if os.path.basename(linker[i]) == 'ld_so_aix':
+-                        # AIX platforms prefix the compiler with the ld_so_aix
+-                        # script, so we need to adjust our linker index
+-                        offset = 1
++                    if target_desc == CCompiler.EXECUTABLE:
++                        linker = self.linker_exe[:]
+                     else:
+-                        offset = 0
+-
+-                    linker[i+offset] = self.compiler_cxx[i]
++                        linker = self.linker_so[:]
+ 
+                 if sys.platform == 'darwin':
+                     linker = _osx_support.compiler_fixup(linker, ld_args)
+diff --git a/Makefile.pre.in b/Makefile.pre.in
+index 35ca1a8..cfa79df 100644
+--- a/Makefile.pre.in
++++ b/Makefile.pre.in
+@@ -618,10 +618,10 @@ sharedmods: $(BUILDPYTHON) pybuilddir.txt Modules/_math.o
+ 	    *\ -s*|s*) quiet="-q";; \
+ 	    *) quiet="";; \
+ 	esac; \
+-	echo "$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' \
++	echo "$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' CFLAGS='$(PY_CFLAGS)' \
+ 		_TCLTK_INCLUDES='$(TCLTK_INCLUDES)' _TCLTK_LIBS='$(TCLTK_LIBS)' \
+ 		$(PYTHON_FOR_BUILD) $(srcdir)/setup.py $$quiet build"; \
+-	$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' \
++	$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' CFLAGS='$(PY_CFLAGS)' \
+ 		_TCLTK_INCLUDES='$(TCLTK_INCLUDES)' _TCLTK_LIBS='$(TCLTK_LIBS)' \
+ 		$(PYTHON_FOR_BUILD) $(srcdir)/setup.py $$quiet build
+ 
diff --git a/packages/python/rpath-non-gcc.patch b/packages/python/rpath-non-gcc.patch
new file mode 100644
index 0000000000000000000000000000000000000000..f203bbbaa5f2866561b78ec996d82f63e750227a
--- /dev/null
+++ b/packages/python/rpath-non-gcc.patch
@@ -0,0 +1,15 @@
+--- a/Lib/distutils/unixccompiler.py	2009-05-09 21:55:12.000000000 +1000
++++ b/Lib/distutils/unixccompiler.py	2017-05-13 14:30:18.077518999 +1000
+@@ -299,10 +299,8 @@
+                 else:
+                     return "-Wl,-R" + dir
+             else:
+-                # No idea how --enable-new-dtags would be passed on to
+-                # ld if this system was using GNU ld.  Don't know if a
+-                # system like this even exists.
+-                return "-R" + dir
++                # Patched by spack to use gcc syntax by default:
++                return "-Wl,-R" + dir
+ 
+     def library_option(self, lib):
+         return "-l" + lib
diff --git a/packages/python/tkinter-3.10.patch b/packages/python/tkinter-3.10.patch
new file mode 100644
index 0000000000000000000000000000000000000000..e06be826b2ee203db1d33410799d4eff09030a5a
--- /dev/null
+++ b/packages/python/tkinter-3.10.patch
@@ -0,0 +1,11 @@
+--- a/setup.py	2021-12-06 12:23:39.000000000 -0600
++++ b/setup.py	2021-12-14 10:30:33.000000000 -0600
+@@ -2099,6 +2099,8 @@
+         #
+         # Detection stops at the first successful method.
+ 
++        return False
++
+         # Check for Tcl and Tk at the locations indicated by _TCLTK_INCLUDES
+         # and _TCLTK_LIBS environment variables.
+         if self.detect_tkinter_fromenv():
diff --git a/packages/python/tkinter-3.11.patch b/packages/python/tkinter-3.11.patch
new file mode 100644
index 0000000000000000000000000000000000000000..fe2d54bd43cc8020c582d0b9f2a61a1b67208794
--- /dev/null
+++ b/packages/python/tkinter-3.11.patch
@@ -0,0 +1,25 @@
+From a49e95e44961a0b6703ef9cb577d2ae5334c4a62 Mon Sep 17 00:00:00 2001
+From: Harmen Stoppels <harmenstoppels@gmail.com>
+Date: Thu, 3 Nov 2022 13:54:00 +0100
+Subject: [PATCH] disable tkinter explicitly
+
+---
+ setup.py | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/setup.py b/setup.py
+index 15d0d45..642adb3 100644
+--- a/setup.py
++++ b/setup.py
+@@ -1358,7 +1358,7 @@ class PyBuildExt(build_ext):
+         self.detect_decimal()
+         self.detect_ctypes()
+         self.detect_multiprocessing()
+-        self.detect_tkinter()
++        # self.detect_tkinter()
+         self.detect_uuid()
+ 
+         # Uncomment the next line if you want to play with xxmodule.c
+-- 
+2.38.1
+
diff --git a/packages/python/tkinter-3.7.patch b/packages/python/tkinter-3.7.patch
new file mode 100644
index 0000000000000000000000000000000000000000..87e19018077b8739eab81306617d06826a236ce5
--- /dev/null
+++ b/packages/python/tkinter-3.7.patch
@@ -0,0 +1,17 @@
+diff -Naur a/setup.py b/setup.py
+--- a/setup.py	2019-01-13 18:59:14.000000000 -0600
++++ b/setup.py	2019-01-13 19:00:31.000000000 -0600
+@@ -1787,13 +1787,6 @@
+         if self.detect_tkinter_explicitly():
+             return
+ 
+-        # Rather than complicate the code below, detecting and building
+-        # AquaTk is a separate method. Only one Tkinter will be built on
+-        # Darwin - either AquaTk, if it is found, or X11 based Tk.
+-        if (host_platform == 'darwin' and
+-            self.detect_tkinter_darwin(inc_dirs, lib_dirs)):
+-            return
+-
+         # Assume we haven't found any of the libraries or include files
+         # The versions with dots are used on Unix, and the versions without
+         # dots on Windows, for detection by cygwin.
diff --git a/packages/python/tkinter-3.8.patch b/packages/python/tkinter-3.8.patch
new file mode 100644
index 0000000000000000000000000000000000000000..a1fc5729aaa3327b794d3223f6311cc8befcd02d
--- /dev/null
+++ b/packages/python/tkinter-3.8.patch
@@ -0,0 +1,12 @@
+diff -Naur a/setup.py b/setup.py
+--- a/setup.py.orig	2021-09-29 21:28:23.000000000 -0400
++++ a/setup.py	2021-09-29 21:28:44.000000000 -0400
+@@ -1826,6 +1826,8 @@
+     def detect_tkinter(self):
+         # The _tkinter module.
+
++        return False
++
+         # Check whether --with-tcltk-includes and --with-tcltk-libs were
+         # configured or passed into the make target.  If so, use these values
+         # to build tkinter and bypass the searches for Tcl and TK in standard