windows - 在 Windows 上编译用 Zig 编写的 CPython 扩展

标签 windows visual-c++ cpython zig

Zig 能够导入 C 库,因此可用于编写 CPython 扩展并编译它。这对我来说可能真的很有用。

这是我的 simple.zig Python 扩展

const py = @cImport({
    @cDefine("PY_SSIZE_T_CLEAN", {});
    @cInclude("Python.h");
});
const std = @import("std");
const print = std.debug.print;

const PyObject = py.PyObject;
const PyMethodDef = py.PyMethodDef;
const PyModuleDef = py.PyModuleDef;
const PyModuleDef_Base = py.PyModuleDef_Base;
const Py_BuildValue = py.Py_BuildValue;
const PyModule_Create = py.PyModule_Create;
const METH_NOARGS = py.METH_NOARGS;

fn hello(self: [*c]PyObject, args: [*c]PyObject) callconv(.C) [*]PyObject {
    _ = self;
    _ = args;
    print("welcom to ziglang\n", .{});
    return Py_BuildValue("");
}

var Methods = [_]PyMethodDef{
    PyMethodDef{
        .ml_name = "hello",
        .ml_meth = hello,
        .ml_flags = METH_NOARGS,
        .ml_doc = null,
    },
    PyMethodDef{
        .ml_name = null,
        .ml_meth = null,
        .ml_flags = 0,
        .ml_doc = null,
    },
};

var module = PyModuleDef{
    .m_base = PyModuleDef_Base{
        .ob_base = PyObject{
            .ob_refcnt = 1,
            .ob_type = null,
        },
        .m_init = null,
        .m_index = 0,
        .m_copy = null,
    },
    .m_name = "simple",
    .m_doc = null,
    .m_size = -1,
    .m_methods = &Methods,
    .m_slots = null,
    .m_traverse = null,
    .m_clear = null,
    .m_free = null,
};

pub export fn PyInit_simple() [*]PyObject {
    return PyModule_Create(&module);
}

当我使用 Zig 编译器编译用 Zig 编写的 CPython 扩展时,Python 无法导入 DLL。我使用的是 Windows 10。

zig build-lib -lc -dynamic -target x86_64-windows-msvc -I"C:\Users\me\Anaconda3\include" -L"C:\Users\me\Anaconda3\libs" -l"python39" simple.zig

当我尝试导入 simple.dll 时,Python 说找不到模块。我正在使用 os 模块将包含扩展 DLL 的目录添加到扩展搜索位置,我相信自 Python 3.8 起 Windows 上就需要这样做。

import os
os.add_dll_directory(r"C:\Users\me\my_zig_project")
import simple
ModuleNotFoundError: No module named 'simple'

我怀疑问题在于 Windows 上的 CPython 是使用 MSVC 编译器编译的(MSVC 的版本取决于 Python 版本),并且即使我将目标环境指定为 Windows MSVC,Zig 编译器也不兼容。

有没有办法编译用 Zig 编写的 CPython 扩展以在 Windows 上运行?

如果可能的话,我们将非常感激一个最小的例子。

最佳答案

我无法使用典型的 setuptools 方法来使用 Zig 创建 Python 模块,但我已经能够使用 wheel module 用于创建链接使用 Zig 编译的 DLL 文件的模块,然后可以使用 Pip 安装这些文件。这是一个最小的例子。

您需要安装setuptoolswheel如果您的系统上尚未安装模块,请先安装它们。我的灵感来自this informative SO answer .

创建如下目录结构:

hello_zig_mod/
|
|-- setup.py
|
|-- hello/
    |
    |-- __init__.py
    |
    |-- hello.zig

hello.zig 文件是将被编译为 DLL 的 Zig 代码:

const std = @import("std");

pub export fn message(msg: [*c]const u8) void {
    std.debug.print("Hello, {s}!\n", .{std.mem.span(msg)});
}

__init__.py 文件是一个用于初始化模块的 Python 文件。它链接到 DLL 并将其中的 message 函数包装在 Python 函数中:

from ctypes import *
import os
lib_path = os.path.join(os.path.dirname(__file__), 'hello.dll')
lib = CDLL(lib_path)

def message(msg):
    lib.message(bytes(msg, 'utf-8'))

setup.py 文件用于构建可由 Pip 安装的 Wheel。您可以在 the answer I linked above 阅读有关此文件的更多详细信息。 .

from setuptools import setup, Distribution

class BinaryDistribution(Distribution):
    def has_ext_modules(foo):
        return True

setup(
    name="hello",
    packages=['hello'],
    package_data={
        'hello':['hello.dll'],
    },
    distclass=BinaryDistribution
)

进入 hello/ 目录并使用 Zig 编译器构建动态库。

> zig build-lib .\hello.zig -dynamic

这将构建 DLL 以及其他一些工件。现在返回 hello_zig_mod 目录并构建轮子:

> python setup.py bdist_wheel

这将在 dist\ 中将轮子与其他工件一起构建为 .whl 文件。现在您终于可以使用 Pip 安装轮子了:

> pip install .\dist\hello-0.0.0-cp312-cp312-win_amd64.whl

checkin Python REPL:

>>> import hello
>>> hello.message("Zig Module")
Hello, Zig Module!

关于windows - 在 Windows 上编译用 Zig 编写的 CPython 扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77466479/

相关文章:

c++ - 如何检测不同的Windows目标平台?

c - Windows 内核驱动程序 : How to determine if thread terminated?

windows - 您可以从 Mac 上运行的 Ruby 连接到 MS Access 数据库吗?

c++ - 使用 Visual C++ 在单独的文件中提取调试信息

Python C 模块 - Malloc 在特定版本的 Python 中失败

java - 如何通过 JDBC 访问 Windows 版 Blackfish?

c++ - "int* ptr = int()"值初始化如何不非法?

c++ - 在 C++ 中与复制构造函数作斗争

c++ - 在 C++ 的 python 类中指定静态变量

python - 在 Python 中使用 long 与 int 的性能影响