I am currently developping a TreeSet/TreeMap package using an underlying C RedBlack tree library. I have developped a wrapper extension and in order to limit the number of binary wheels, I have used the stable ABI. To build the package distributions, I use build
with a pyproject.toml
configuration file, and setuptools
as the backend.
The command python -m build
(or pip install .
) can only build a wheel tagged -cpxx-cpxx-platform
(eg -cp38-cp38-linux_x86_64.whl
on Linux or -0.1.0-cp310-cp310-win_amd64.whl
on Windows). Using directly setuptools
with a setup.py
and a setup.config
file, it is possible to build a wheel tagged as cpxx-abi3-platform
with the command:
python setup.py bdist_wheel --py-limited-api=cpxx
but I could not find a way to pass the py-limited-api parameter to build
pyproject.toml
[build-system]
requires = ["setuptools>=60.0", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "empty"
version = "0.1.0"
authors = [
{ name="SBA", email="s-ball@laposte.net" },
]
description = "Simple demo"
readme = "README.md"
license = { file="LICENSE.txt" }
requires-python = ">=3.8"
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Programming Language :: C",
]
setup.py
from setuptools import setup, Extension
import os.path
kwargs = dict(
# more metadata
ext_modules=[
Extension('empty.ext', [os.path.join('empty', 'ext.c')],
py_limited_api=True,
)]
)
setup(**kwargs)
ext.c
#define Py_LIMITED_API 0x03070000
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <structmember.h>
// The module object
static PyObject* mod = NULL;
/*
* Documentation for _rbtree.
*/
PyDoc_STRVAR(ext_doc, "Minimal extension module");
static PyObject *say_hello(PyObject *mod, PyObject *args) {
return PyUnicode_FromString("Hello !");
}
PyMethodDef methods[] = {
{"hello", &say_hello, METH_NOARGS, PyDoc_STR("Simple function")},
{NULL},
};
static PyModuleDef ext_def = {
PyModuleDef_HEAD_INIT,
"ext",
ext_doc,
-1, /* m_size */
.m_methods=methods,
};
PyMODINIT_FUNC PyInit_ext() {
mod = PyModule_Create(&ext_def);
return mod;
}
and an empty __init__.py
file to declare a normal package.
I could not find anything about abi3 wheels anywhere in build documentation, nor in the Python Packaging User Guide where only version tagged build packaging are documented.
I could produce the expected wheels by manually unpacking a version tagged wheel (wheel unpack ...whl
), changing its RECORD
file, and packing it back (wheel pack ...
)
Reverting to a good old python setup.py ...
solution can directly build the correctly tagged wheel, but I am afraid that it is now legacy if not deprecated...
It is damned simple! The key is that if parameters cannot be passed (at least not simply) in the command line, they can be declared in config files. So here a simple solution is to add a setup.cfg
with a [build_wheel]
section:
[bdist_wheel]
py_limited_api=cp37
That is enough for the module in charge of the creation of the wheel to find its parameter and correctly build wheel tagged with cp37-abi3-platform