Building on @encukou’s comments, here’s a modification of the original proposal. (Don’t focus too much on naming, we can work out those details later.)
Here’s a prototype: Prototype ABI4 with Python 3.7+ compatibility · colesbury/cpython@2c1d02a · GitHub
- We add a new “abi4” with targets “cp37-abi4”, …, “cp313-abi4”.
- C extensions can target by “abi4” by defining
Py_ABI_VERSION_4along with the usualPy_LIMITED_API=0x30... - The
--disable-gilbuilds can load “abi4” wheels, but not “abi3” wheels. So “cp37-abi4” wheels are compatible with Python 3.7+, including--disable-gilbuilds. PyObjectandPyVarObjectbecome opaque structs in abi4.PyObject_HEADis still needed for extensions to define their own types. In abi4, it reserves enough space for both abi3 PyObject headers and--disable-gilPyObject headers. This means 24 or 32 bytes on 32-bit or 64-bit platforms. Note that extra space in the header is fine.PyModuleDefis a bit different. It reserves exactly the space for an abi3 PyObject header. (It can’t be bigger because older versions of CPython still need to access the fields.) At the API level,PyModuleDef_Initno longer guarantees that it returns “def cast toPyObject*”. Old versions of CPython, of course, still do this as does the default build of CPython 3.13. The--disable-gilbuilds return a simple wrapper.
The implementations of Py_TYPE and similar require special care when targeting pre-3.13 versions of Python and ABI 4. (See this file).
- Extensions must call the
Py_Typefunction in 3.13, but that won’t be available in 3.12 and older. When loaded on those versions, the extension must access the field directly. - On most platforms, we handle this by making
Py_Typea weak symbol. Windows doesn’t support weak symbols, so we useGetProcAddressinstead to determine ifPy_Typeis available. - There’s a dispatcher mechanism so that we only have to look up the symbol on the first invocation.
Risks and weird stuff
- Wheels can be named like
cryptography-42.0.0-cp37-abi4-[platform].whlbut the actual shared libraries will still need to be named with the.abi3.soextension to be loadable by older versions of Python. - pip (or more specifically pypa/packaging) will needed to disallow abi3 wheels from
--disable-gilbuilds and allowabi4wheels for Python 3.7+.