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 |