setuptools扩展,用于使用Zig构建cpython扩展。
项目描述
这是一个setuptools扩展,用于使用Zig编译器构建用Zig和/或C编写的cpython扩展。
此扩展期望在您的PATH中找到zig命令。如果它不在那里,或者如果您需要选择特定的版本,您可以设置环境变量PY_ZIG为可执行文件的完整路径。例如:
PY_VER=/usr/local/bin/zig
此模块版本的已更新到Zig 0.10.0,但应与其他版本兼容(只要您适应您的Zig代码)。它已在Ubuntu 22.4(二进制zig安装)和macOS 13.0.1(brew安装)上与Python 3.7 - 3.11进行了测试。
PyPI上有setuptools-zig软件包,但不需要安装,因为它是一个设置需求。一旦您的setup.py文件有适当的条目,构建sdist或bdist_wheel将自动下载软件包(缓存在.eggs目录中)。
setup.py
您的setup.py文件应如下所示
from setuptools import Extension from setuptools import setup setup( name=NAME, version='MAJ.MIN.PATCH', python_requires='>=3.7.15%', build_zig=True, ext_modules=[Extension(NAME, [XX1, XX2])], setup_requires=['setuptools-zig'], )
其中NAME由您的软件包名称替换。将MAJ、MIN和PATCH替换为您的软件包版本,XX1、XX2为您的源文件(您可以只有一个,也可以有多个)。
将此适用于您的项目
python setup.py bdist_wheel
将在您的dist目录中生成一个.whl文件。此wheel文件可以在虚拟环境中安装,并且可以导入和使用包中定义的函数。默认情况下,编译和/或链接命令执行将显示,只有在发生错误时才会显示输出。可以通过指定-v或-vv来增加详细程度,在bdist_wheel之后。
将Zig用作C编译器
创建您的 setup.py
from setuptools import Extension from setuptools import setup setup( name='c_sum', version='1.0.0', python_requires='>=3.7.15', build_zig=True, ext_modules=[Extension('c_sum', ['sum.c', ])], setup_requires=['setuptools-zig'],
和 sum.c
/* based on https://docs.pythonlang.cn/3.9/extending/extending.html */ #define PY_SSIZE_T_CLEAN #include <Python.h> PyObject* sum(PyObject* self, PyObject* args) { long a, b; if (!PyArg_ParseTuple(args, "ll", &a, &b)) return NULL; return PyLong_FromLong(a+b); } static struct PyMethodDef methods[] = { {"sum", (PyCFunction)sum, METH_VARARGS}, {NULL, NULL} }; static struct PyModuleDef zigmodule = { PyModuleDef_HEAD_INIT, "sum", NULL, -1, methods }; PyMODINIT_FUNC PyInit_c_sum(void) { return PyModule_Create(&zigmodule);
使用 pip 安装生成的 wheel 文件并使用
python -c "from c_sum import sum; print(sum(20, 22))"
使用 Zig 与 .zig 和 .c
Zig 编译器可以轻松混合搭配(见 macOS 部分),这里我们使用 C 代码提供接口,并在 Zig 中执行计算总和的重劳工作。
setup.py:
from setuptools import Extension from setuptools import setup setup( name='c_zig_sum', version='1.0.0', python_requires='>=3.7.15', build_zig=True, ext_modules=[Extension('c_zig_sum', ['c_int.c', 'sum.zig', ])], setup_requires=['setuptools-zig'], )
c_int.c:
/* based on https://docs.pythonlang.cn/3.9/extending/extending.html */ #define PY_SSIZE_T_CLEAN #include <Python.h> PyObject* sum(PyObject* , PyObject*); /* PyObject* sum(PyObject* self, PyObject* args) { long a, b; if (!PyArg_ParseTuple(args, "ll", &a, &b)) return NULL; return PyLong_FromLong(a+b); } */ static struct PyMethodDef methods[] = { {"sum", (PyCFunction)sum, METH_VARARGS}, {NULL, NULL} }; static struct PyModuleDef zigmodule = { PyModuleDef_HEAD_INIT, "c_zig_sum", NULL, -1, methods }; PyMODINIT_FUNC PyInit_c_zig_sum(void) { return PyModule_Create(&zigmodule); }
sum.zig:
const c = @cImport({ @cDefine("PY_SSIZE_T_CLEAN", "1"); @cInclude("Python.h"); }); pub export fn sum(self: [*]c.PyObject, args: [*]c.PyObject) [*c]c.PyObject { var a: c_long = undefined; var b: c_long = undefined; _ = self; if (!(c._PyArg_ParseTuple_SizeT(args, "ll", &a, &b) != 0)) return null; return c.PyLong_FromLong((a + b));
Zig 代码仅
原始转换的代码难以阅读。在 Python 3.7/3.8/3.9/3.10/3.11 之间,从 C 转换的特定程序 Zig 代码没有差异(但当然在头文件中有差异)。这是一个尝试整理事物的初步尝试。仅需要在注释行下的部分需要根据您的项目进行适配。
setup.py:
from setuptools import Extension from setuptools import setup setup( name='zig_sum', version='1.0.1', python_requires='>=3.7.15', build_zig=True, ext_modules=[Extension('zig_sum', ['sum.zig' ])], setup_requires=['setuptools-zig'], )
sum.zig:
const c = @cImport({ @cDefine("PY_SSIZE_T_CLEAN", "1"); @cInclude("Python.h"); }); const PyObject = c.PyObject; const PyModuleDef_Base = extern struct { ob_base: PyObject, // m_init: ?fn () callconv(.C) [*c]PyObject = null, m_init: ?*const fn () callconv(.C) [*c]PyObject = null, m_index: c.Py_ssize_t = 0, m_copy: [*c]PyObject = null, }; const PyModuleDef_HEAD_INIT = PyModuleDef_Base { .ob_base = PyObject { .ob_refcnt = 1, .ob_type = null, } }; const PyMethodDef = extern struct { ml_name: [*c]const u8 = null, ml_meth: c.PyCFunction = null, ml_flags: c_int = 0, ml_doc: [*c]const u8 = null, }; const PyModuleDef = extern struct { // m_base: c.PyModuleDef_Base, m_base: PyModuleDef_Base = PyModuleDef_HEAD_INIT, m_name: [*c]const u8, m_doc: [*c]const u8 = null, m_size: c.Py_ssize_t = -1, m_methods: [*]PyMethodDef, m_slots: [*c]c.struct_PyModuleDef_Slot = null, m_traverse: c.traverseproc = null, m_clear: c.inquiry = null, m_free: c.freefunc = null, }; ///////////////////////////////////////////////// pub export fn sum(self: [*]PyObject, args: [*]PyObject) [*c]PyObject { var a: c_long = undefined; var b: c_long = undefined; _ = self; if (!(c._PyArg_ParseTuple_SizeT(args, "ll", &a, &b) != 0)) return null; return c.PyLong_FromLong((a + b)); } pub var methods = [_:PyMethodDef{}]PyMethodDef{ PyMethodDef{ .ml_name = "sum", .ml_meth = @ptrCast(c.PyCFunction, @alignCast(@import("std").meta.alignment(c.PyCFunction), &sum)), .ml_flags = @as(c_int, 1), .ml_doc = null, }, }; pub var zigmodule = PyModuleDef{ .m_name = "zig_sum", .m_methods = &methods, }; pub export fn PyInit_zig_sum() [*c]c.PyObject { return c.PyModule_Create(@ptrCast([*c]c.struct_PyModuleDef, &zigmodule)); }
macOS
在 macOS 上运行 zig build-lib 将生成一个无法由 Python 加载的 .dylib 文件。相反,setuptools-zig 将对单个源文件运行 zig build-obj(因为将 .c 和 .zig 文件组合会导致错误),然后使用 clang -bundle 将 .o 文件组合起来,生成可加载的 .so 文件。
清理
在 Zig 0.10.0 中运行 zig build-obj sum.zig 会生成 sum.o 和 sum.o.o 两个文件。此扩展尝试清理这些额外的文件。
项目详情
setuptools_zig-0.2.0.tar.gz 的散列
算法 | 散列摘要 | |
---|---|---|
SHA256 | f248ba066bc66885a8035e1c1713f74f9a28735a7916d643f0da95071fa45322 |
|
MD5 | 853c0d147133798be7638c9a11773477 |
|
BLAKE2b-256 | 24837abe110441f7bb46312f94d5d1d7ee5d6ec9273052aad8bda8a369fc876a |
setuptools_zig-0.2.0-py3-none-any.whl 的散列
算法 | 散列摘要 | |
---|---|---|
SHA256 | bba60f68a70474ccbd3d51d5386f26e48b165758ae972bf0117d0fe373a0ac6f |
|
MD5 | a9308a10b066e51b035ab7995c32f9ba |
|
BLAKE2b-256 | 0b0afca1d1b0a480b5f5897b8dc655840c675efcc4fb919f0f1e27d16e9f3f3f |