Windows下Zig编写CPython扩展编译后无法导入求解决方案
Windows下用Zig编译CPython扩展的可行方案
问题描述
尝试用Zig编写CPython扩展,代码如下:
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("welcome 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 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
编译生成DLL后,通过os.add_dll_directory添加路径后导入仍报错:
import os os.add_dll_directory(r"C:\Users\me\my_zig_project") import simple # ModuleNotFoundError: No module named 'simple'
怀疑是Windows下MSVC编译的CPython与Zig编译的DLL存在兼容性问题,求可行方案及最小示例。
可行方案及最小示例
Windows下用Zig编译CPython扩展完全可行,问题核心在于DLL命名规则和编译参数细节,以下是修正后的完整流程:
1. 修正后的Zig扩展代码(simple.zig)
const py = @cImport({ @cDefine("PY_SSIZE_T_CLEAN", {}); @cInclude("Python.h"); }); const std = @import("std"); // 简化类型别名 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(_: [*c]PyObject, _: [*c]PyObject) callconv(.C) [*]PyObject { std.debug.print("Welcome to Zig-powered Python extension!\n", .{}); return Py_BuildValue(""); } // 方法列表(必须以空结构体结尾) const methods = [_]PyMethodDef{ .{ .ml_name = "hello", .ml_meth = hello, .ml_flags = METH_NOARGS, .ml_doc = "Print a welcome message from Zig", }, .{ .ml_name = null, .ml_meth = null, .ml_flags = 0, .ml_doc = null }, }; // 模块定义 const module_def = 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 = "A minimal Zig-based Python extension", .m_size = -1, .m_methods = &methods, .m_slots = null, .m_traverse = null, .m_clear = null, .m_free = null, }; // 模块初始化函数(必须导出,命名规则:PyInit_{模块名}) pub export fn PyInit_simple() [*]PyObject { return PyModule_Create(&module_def); }
2. 正确的编译命令
Windows下CPython扩展要求DLL文件名必须为{模块名}.pyd,因此编译时需指定输出文件名:
zig build-lib -lc -dynamic -target x86_64-windows-msvc ^ -I"C:\Users\me\Anaconda3\include" ^ -L"C:\Users\me\Anaconda3\libs" ^ -lpython39 ^ -o simple.pyd ^ simple.zig
注意:
- 替换
C:\Users\me\Anaconda3为你的Python安装路径-lpython39对应Python 3.9,根据你的版本调整(如Python 3.10则为-lpython310)- 必须指定
-o simple.pyd,否则Zig默认生成simple.dll,Python无法识别为扩展模块
3. 测试导入
将生成的simple.pyd放在任意目录,运行以下Python代码:
import os # 添加pyd文件所在目录到搜索路径 os.add_dll_directory(r"C:\Users\me\my_zig_project") import simple simple.hello() # 输出:Welcome to Zig-powered Python extension!
关键注意事项
- 文件名后缀:Windows下Python扩展必须是
.pyd后缀,而非.dll,这是之前报错的核心原因 - 目标平台匹配:确保Zig的
-target参数与Python的架构一致(如Python是x86_64则用x86_64-windows-msvc,32位则用i386-windows-msvc) - Python版本对应:链接的Python库版本必须与运行时的Python版本完全一致,否则会出现导入错误或运行时崩溃
- 调用约定:所有导出给Python的函数必须使用
callconv(.C),确保与C调用约定兼容
内容的提问来源于stack exchange,提问作者geoff22873
相关产品推荐
相关产品推荐

