Как создать модуль расширения Python, совместимый с PEP384, и упаковать его с правильным тегом ABI3?
mymodule.c начинается следующим образом:
#define PY_SSIZE_T_CLEAN
#define Py_LIMITED_API 0x03070000
#include "Python.h"
Сборка без ошибок и предупреждений. Тем не менее, результирующий файл называется
mymodulename.cpython-37m-x86_64-linux-gnu.so
Команда сборки:
$ python setup.py build
Когда я выдаю вместо этого
$ pip wheel .
расширение, содержащееся в колесе, называется так же, и, следовательно, колесо также не имеет тега ABI3.
Я ожидал имя файла с abi3 или подобным, как указано в PEP 425.
Мои исследования до сих пор разочаровывали. Я просмотрел PEP 384 и 425, документы и соответствующие руководства на docs.python.org, в частности его C/API и distutils, документы от PYPA, документы по setuptools, wheel и pip — безрезультатно.
Файл /modules/xxmodule.c, содержащийся в текущем исходном дистрибутиве Python, представляет просто исторический интерес.
Что мне здесь не хватает?
1 ответ
Это зависит от бэкэнда; не все бэкенды сборки поддерживают PEP 384.
Например, при использовании чистого (так
from distutils.core import setup
setup(...)
), нет возможности изменить суффикс расширения; вот почему мне пришлось задать вопрос об изменении правил именования Cython для файлов .so несколько лет назад. Но вы не должны использовать чистый
distutils
в любом случае в настоящее время, так что этот раздел только ради полноты.
Если вы используете
setuptools
, вы должны пройти
py_limited_api=True
при создании
Extension
объекты. Пример:
from setuptools import setup, Extension
setup(
...,
ext_modules=[
# this extension will have the SOABI suffix, e.g.
# cpython-37m-darwin or cpython-39-x86_64-linux-gnu etc.
Extension("foo", ["foo.c"]),
# this extension will have the `abi3.so` suffix
Extension("bar", ["bar.c"], py_limited_api=True),
],
)
Бонус: если вы создаете модули расширения из кода Rust и используете
setuptools_rust
, создание расширений, совместимых с PEP 384, теперь также возможно, начиная с версии 0.11.4:
from setuptools import setup
from setuptools_rust import RustExtension
setup(
...,
rust_extensions=[
RustExtension("foo.rust", py_limited_api=True, features=["pyo3/abi3"]),
],
)
: построение правильного тега колеса
Когда я выпускаю
$ pip wheel .
расширение, содержащееся в колесе, называется так же, и, следовательно, колесо также не имеет тега ABI3.
Тег колеса — это несколько другая история; он не зависит от имен расширений, которые он упаковывает. Чтобы установить ограниченный ABI, при построении колеса обычным способом можно было бы выдать
$ python setup.py bdist_wheel --py-limited-api=cp37
Полученное колесо будет иметь имя
<pkg>-<ver>-cp37-abi3-<platform>.whl
.
Однако это не будет работать с
pip wheel
поскольку вы не можете передавать параметры подкоманде. Таким образом, вы можете сохранить его в:
# setup.cfg
[bdist_wheel]
py_limited_api = cp37
При работе
pip wheel .
в настоящее время,
bdist_wheel
подберет вариант из
setup.cfg
и соберите правильное имя колеса.