You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 06:27:03