0%

在Visual Studio中开发pyd动态库模块

Visual Studio依赖

在Visual Studio 2017之前版本需要手动搭建Python的pyd模块开发环境,Visual Studio 2017或更高版本,可安装Python开发工作负载,其内包含了Python本机开发工具,可以直接使用Python 扩展模块模板来初始化pyd项目。

以Python扩展模块模板创建项目

项目生成的实际上就是dll模块,不过会把目标文件扩展名修改为pyd,同时会把Python相关的头文件库文件路径自动引入进来。另外该模板使用的调试器是Python/Native Debugging,调试时会启动一个Python Shell,并自动把项目模块import进来。

Notes:如果需要依赖第三方的动态库,可以考虑调整项目调试的工作目录

如果想要单独创建一个测试用例项目可以这么做,创建一个Python子项目,然后把pyd模块的生成路径包含进搜索路径中,不过一般可能没这个必要,看实际需求。

开发相关指引

  • Python模块的公用头文件是Python.h
  • 写pyd模块的目的有可能是为某个还没有Python Binding的库编写Wrapper,那么可以在项目中把该库的头文件和库文件路径引入进来
  • 需要注意32位或64位匹配
  • 具体的开发方式以及结构组织请直接看官方文档

相关开发手册和Example可查看以下链接:

关于混合模式调试和调试符号

如果需要安装Python的调试符号和调试工具,新版本Python需要在安装程序中指定下载。

关于Visual Studio中的混合模式调试可查看以下链接:

示例说明

模块名:BytertcSDKWrapper

模块内方法:example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <Python.h>

/*
* 实现example方法.
*/

// example方法的文档说明
PyDoc_STRVAR(BytertcSDKWrapper_example_doc, "example(obj, number)\
\
Example function");

// example方法实现
PyObject *BytertcSDKWrapper_example(PyObject *self, PyObject *args, PyObject *kwargs) {
/* Shared references that do not need Py_DECREF before returning. */
PyObject *obj = NULL;
int number = 0;

/* Parse positional and keyword arguments */
static char* keywords[] = { "obj", "number", NULL };
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oi", keywords, &obj, &number)) {
return NULL;
}

/* Function implementation starts here */

if (number < 0) {
PyErr_SetObject(PyExc_ValueError, obj);
return NULL; /* return NULL indicates error */
}

Py_RETURN_NONE;
}

/*
* 列出加入BytertcSDKWrapper模块的所有方法,在exec_BytertcSDKWrapper中使用.
*/
static PyMethodDef BytertcSDKWrapper_functions[] = {
{ "example", (PyCFunction)BytertcSDKWrapper_example, METH_VARARGS | METH_KEYWORDS, BytertcSDKWrapper_example_doc },
{ NULL, NULL, 0, NULL } /* 标注结尾 */
};

/*
* 初始化BytertcSDKWrapper模块,可能会被多次调用,所以需要避免使用static状态.
*/
int exec_BytertcSDKWrapper(PyObject *module) {
// 注册要添加的方法
PyModule_AddFunctions(module, BytertcSDKWrapper_functions);

// 添加一些模块的元信息
PyModule_AddStringConstant(module, "__author__", "huzhiqin");
PyModule_AddStringConstant(module, "__version__", "1.0.0");
PyModule_AddIntConstant(module, "year", 2022);

return 0; /* success */
}

/*
* BytertcSDKWrapper模块文档信息.
*/
PyDoc_STRVAR(BytertcSDKWrapper_doc, "The BytertcSDKWrapper module");

/*
* 模块slot,有create和exec slot,这里登记的是exec.
*
* @notes: New in 3.5
*/
static PyModuleDef_Slot BytertcSDKWrapper_slots[] = {
{ Py_mod_exec, exec_BytertcSDKWrapper },
{ 0, NULL }
};

/*
* 模块定义.
*/
static PyModuleDef BytertcSDKWrapper_def = {
PyModuleDef_HEAD_INIT,
"BytertcSDKWrapper", /* 模块名字,必须与“配置属性”>“常规”>“目标名称”一致 */
BytertcSDKWrapper_doc, /* 模块文档描述 */
0, /* m_size */
NULL, /* m_methods */
BytertcSDKWrapper_slots, /* create or exec */
NULL, /* m_traverse */
NULL, /* m_clear */
NULL, /* m_free */
};

/*
* 导出BytertcSDKWrapper模块,必须以PyInit_<module-name>,这样的方式命名.
*/
PyMODINIT_FUNC PyInit_BytertcSDKWrapper() {
return PyModuleDef_Init(&BytertcSDKWrapper_def);
}
请我喝瓶肥仔快乐水?

欢迎关注我的其它发布渠道